MySQL執行計劃(explain)分析

MySQL執行計劃(explain)分析

  • EXPLAIN支持對SELECT、UPDATE、INSERT、REPLACE、DELETE分析

  • 執行計劃能知道:

    • SQL如何使用索引
    • 聯接查詢的執行順序
    • 查詢掃描的數據行數
  • ID列:

    • 表示執行SELECT語句的順序
    • ID相同時,執行順序由上至下
    • ID越大優先級越高,越優先被執行
  • SELECT_TYPE列:

    • SIMPLE:不包含子查詢或是UNION操作的查詢
    • PRIMARY:查詢中包含任何子查詢,那麼最外層的查詢則被標記爲PRIMARY
    • SUBQUERY:SELECT列表中的子查詢
    • DEPENDENT SUBQUERY:依賴外部結果的子查詢
    • UNION:UNION操作的第二個或是之後的查詢的值爲UNION
    • DEPENDENT UNION:當UNION作爲子查詢時,第二或是第二個後的查詢的SELECT_TYPE值
    • UNION RESULT:UNION產生的結果集
    • DERIVED:出現在FROM子句中的子查詢
    • 用途:查看查詢方法
  • TABLE列:

    • 輸出數據行所在的表的名稱
    • <unionM,N>由ID爲M,N查詢union產生的結果集
    • <derivedN>或<subqueryN>由ID爲N的查詢產生的結果
    • 用途:查看數據來源
  • PARTITIONS列

    • 對於分區表,顯示查詢的分區ID
    • 對於非分區表,顯示爲NULL
    • 用途:用於檢查出低效率的跨分區掃描
  • TYPE列

    • system:這是const聯接類型的一個特例,當查詢的表只有一行時使用
    • const:表中有且只有一個匹配的行時使用,如對主鍵或是唯一索引的查詢,效率最高的聯接方式
    • eq_ref: 唯一索引或主鍵查找,對於每個索引鍵,表中只有一條記錄與之匹配
    • ref:非唯一索引查找,返回匹配某個單獨值的所有行
    • ref_or_null:類似於ref類型的查詢,但是附加了對NULL值列的查詢
    • index_merge:該聯接類型表示使用了索引合併優化方法。
    • range:索引範圍掃描,常見於between、>、<這樣的查詢條件
    • index:全索引撒秒,同ALL的區別是,遍歷的是索引數
    • ALL:全表掃描,效率最差的連接方式
  • EXTRA列

    • distinct:優化distinct操作,在找到第一匹配的元祖後即停止找同樣值的動作
    • not exists:使用Not Exists來優化查詢
    • using filesort:使用額外操作進行排序,通常會出現在order by或group by查詢中
    • using index:使用了覆蓋索引進行查詢
    • using temporary:MySQL需要使用臨時表來處理查詢,常見於排序,子查詢,和分組查詢
    • using where:需要在MySQL服務器層使用WHERE條件來過濾數據
    • select tables optimized away:直接通過索引來獲取數據,不用訪問表(效率最高)
  • POSSIBLE_KEYS列

    • 指出MySQL能使用哪些索引來優化查詢
    • 查詢列所涉及到的列上的索引都會被列出,但不一定會被使用
  • KEY列

    • 查詢優化器優化查詢實際所使用的索引
    • 如果沒有可用的索引,則顯示爲NULL
    • 如查詢使用了覆蓋索引,則該索引僅出現在Key列中
  • KEY_LEN列

    • 表示索引字段的最大可能長度
    • 長度由字段定義計算而來,並非數據的實際長度
  • REF列

    • 表示哪些列或常量被用於查找索引列上的值
  • ROWS列

    • 表示MySQL通過索引統計信息,估算的所需讀取的行數
    • ROWS值的大小是個統計抽樣結果,並不十分準確
  • FILTERED列

    • 表示返回結果的行數佔需讀取行數的百分比
    • FILTERED列的值越大越好
    • 依賴於統計信息

執行計劃的限制

  • 無法展示存儲過程,觸發器,UDF對查詢的影響
  • 無法使用EXPLAIN對存儲過程進行分析
  • 早期版本的MySQL只支持對SELECT語句進行分析

常見業務優化處理

優化評論分頁查詢

例子

SELECT customer_id,title,content FROM `product_comment`
WHERE audit_status=1 AND product_id=199726
LIMIT 0,5

這裏的索引有audit_status和product_id,可以建立聯合索引。但是哪個放左邊就要計算區分度。

計算方法

SELECT COUNT(DISTINCT audit_status)/COUNT(*) AS audit_rate,
COUNT(DISTINCT product_id)/COUNT(*) AS product_rate
FROM product_comment;

區分度越高越好,放左邊。結論product_rate>audit_rate

建立聯合索引

CREATE INDEX idx_productID_auditStatus ON product_comment(product_id,audit_status)

如何刪除重複數據

業務場景:刪除評論表中對同一訂單同一商品的重複評論,只保留最早的一條。

  1. 查看是否存在對於同一訂單同一商品的重複評論。
SELECT order_id,product_id,COUNT(*) FROM product_comment GROUP BY order_id,product_id HAVING COUNT(*)>1;
  1. 備份product_comment表。
CREATE TABLE bak_product_comment_161022 LIKE product_comment;

INSERT INTO bak_product_comment_161022 SELECT * FROM product_comment;
  1. 刪除同一訂單的重複評論。
DELETE a
FROM product_comment a
JOIN(
    SELECT order_id,product_id,MIN(comment_id) AS comment_id
    FROM product_comment
    GROUP BY order_id,product_id
    HAVING COUNT(*)>=2
) b ON a.order_id=b.order_id AND a.product_id=b.product_id
AND a.comment_id>b.comment_id

如何進行分區間數據統計示例

業務場景:統計消費總金額大於1000元的,800到1000元的,500到800元的,以及500元以下的人數。

SELECT COUNT(CASE WHEN IFNULL(total_money,0) >=1000 THEN a.customer_id END) AS '>1000'
      ,COUNT(CASE WHEN IFNULL(total_money,0) >=800 AND IFNULL(total_money,0) <1000 THEN a.customer_id END) AS '800~1000'
      ,COUNT(CASE WHEN IFNULL(total_money,0) >=500 AND IFNULL(total_money,0) <800 THEN a.customer_id END) AS '500~800'
      ,COUNT(CASE WHEN IFNULL(total_money,0) <500  THEN a.customer_id END) AS '<500'
FROM mc_userdb.`customer_login` a
LEFT JOIN
( SELECT customer_id,SUM(order_money) AS total_money
  FROM mc_orderdb.`order_master` GROUP BY customer_id) b
ON a.`customer_id`=b.`customer_id`

捕獲有問題的SQL-慢查日誌

  • 啓動MySQL慢查日誌
set global show_query_log_file = /sql_log/show_log.log

set global log_queries_not_using_indexes = on; -- 未使用索引的SQL記錄日誌

set global long_query_time=0.001; -- 抓取執行超過多少時間的SQL(秒)

set global low_query_log=on; -- 啓動
  • 如何分析慢查日誌,使用mysqldumpslow工具,例如:mysqldumpslow slow-mysql.log

參考

  1. 高性能可擴展MySQL數據庫設計及架構優化 電商項目,sqlercn,https://coding.imooc.com/class/79.html

關於我:

linxinzhe,全棧工程師,目前供職於某世界500強銀行的金融科技部門(人工智能,區塊鏈)。

GitHub:https://github.com/linxinzhe

歡迎留言討論,也歡迎關注我~
我也會關注你的哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章