首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL EXPLAIN 深度解析:從執行計劃到 SQL 優化實戰

     編輯:MySQL 綜合教學

MySQL EXPLAIN 深度解析:從執行計劃到 SQL 優化實戰

EXPLAIN 是 MySQL 性能調優的「核磁共振」,它揭示優化器如何執行查詢:用什麼索引、怎麼關聯表、掃描多少行、是否需要臨時表或排序。熟練讀懂 EXPLAIN 輸出,是寫出高性能 SQL 的前提。本文逐欄位拆解,並結合實戰案例說明優化思路。

核心欄位詳細解讀

1. id — 查詢序列號

標識 SELECT 的執行順序。id 相同按順序執行;id 不同,值越大越先執行(子查詢)。

EXPLAIN SELECT * FROM (SELECT * FROM t1 LIMIT 10) AS d;
-- 衍生表 id=2 先執行,外層 id=1 後執行

2. select_type — 查詢類型

類型含義典型場景
SIMPLE無 UNION/子查詢的簡單查詢單表查詢
PRIMARY最外層查詢包含子查詢的 SQL
SUBQUERYSELECT 列表中的子查詢SELECT (SELECT 1 FROM t2) FROM t1
DERIVEDFROM 子句中的衍生表SELECT * FROM (SELECT * FROM t1) d
UNIONUNION 中第二個及後續 SELECTSELECT 1 UNION SELECT 2
UNION RESULTUNION 結果合併臨時表合併階段

3. table — 訪問的表

顯示該行數據對應的表名,衍生表顯示為 <derivedN>,UNION 結果為 <unionM,N>。

4. type — 訪問類型(核心指標,由優到劣)

此欄位最關鍵,直接反映索引使用效率。

類型說明性能典型場景
system表僅一行(const 特例)極快極少見
const主鍵/唯一索引等值查詢,最多一行匹配極快WHERE id=1
eq_ref唯一索引/主鍵關聯,每張表最多一行匹配極快JOIN ON pk=fk
ref非唯一索引等值查詢/關聯,可能多行匹配快WHERE status=1
ref_or_nullref + NULL 值查詢快WHERE col=1 OR col IS NULL
index_merge多索引合併(intersection/union/sort-union)中等WHERE a=1 OR b=2
range索引範圍掃描中等BETWEEN, IN, >, <, LIKE 'prefix%'
index全索引掃描(不讀數據文件)較慢SELECT idx_col FROM t
ALL全表掃描最差無索引或條件不命中索引

優化目標: 至少達到 range,最好是 ref/eq_ref/const。

5. possible_keys / key / key_len

  • possible_keys:理論上可用的索引
  • key:實際選用的索引(NULL 表示無索引)
  • key_len:索引使用的字節數,推斷聯合索引用了幾列

6. ref — 關聯比較依據

顯示哪個欄位或常數與 key 配合查找。常見值:const(常數)、db.tbl.col(關聯欄位)、func(函數結果)。

7. rows — 預估掃描行數

基於統計信息估算,值越大越差。乘積 反映整體查詢代價。

8. Extra — 額外信息(優化線索寶庫)

值含義優化方向
Using index覆蓋索引,僅讀索引樹優秀,無需回表
Using whereServer 層過濾(存儲引擎返回後再篩選)正常,但若 type=ALL 則需加索引
Using index conditionICP(Index Condition Pushdown),存儲引擎層過濾優於 Using where
Using filesort需額外排序(無索引支持 ORDER BY)加索引消除排序
Using temporary需建臨時表(GROUP BY/DISTINCT/ORDER BY 不同表)優化索引/調整 SQL 結構
Using join buffer使用 Join Buffer(無索引關聯)加關聯索引
Impossible WHEREWHERE 條件永假檢查邏輯錯誤

實戰優化案例:消除 Using temporary + Using filesort

-- 原查詢:驅動表 city,排序非驅動表 ads.id → 產生臨時表+文件排序
EXPLAIN SELECT ads.id FROM ads, city 
WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id = ads.id 
ORDER BY ads.id DESC;

-- 優化:排序驅動表 city.ads_id(等價於 ads.id) → 無臨時表
EXPLAIN SELECT ads.id FROM ads, city 
WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id = ads.id 
ORDER BY city.ads_id DESC;

原理:MySQL 採用 Nested Loop Join,驅動表結果集直接有序則無需臨時表;非驅動表排序需將關聯結果存入臨時表再排序。永遠用小結果集驅動大結果集,且 ORDER BY 跟隨驅動表索引順序。

常見誤區辨析

  1. count(1)/count(pk) 優於 count(*)?錯。MySQL 對 count(*) 有專門優化。
  2. count(col) 等同 count(*)?錯。前者統計非 NULL 行數,後者統計總行數。
  3. select a,b 比 select a,b,c 讀取更少數據?多數情況錯。行式存儲下整行讀取,除非覆蓋索引避免回表。
  4. ORDER BY 一定排序?錯。若索引順序滿足排序需求,優化器會省略排序。
  5. Using filesort 表示磁盤排序?錯。只要有排序操作就顯示,實際可能在內存完成。

優化十大鐵律

  1. 盡量少 JOIN(MySQL 優化器統計信息有限,複雜 JOIN 易誤判)
  2. 盡量少排序(利用索引順序、減少參與排序行數)
  3. 避免 SELECT *(影響覆蓋索引、增加排序/網絡開銷)
  4. JOIN 代替子查詢(MySQL 子查詢執行計劃長期存在缺陷)
  5. 少用 OR,改用 UNION ALL(優化器對 OR 處理較弱)
  6. UNION ALL 代替 UNION(避免唯一性過濾排序)
  7. 盡早過濾(先在驅動表過濾分頁,再關聯)
  8. 避免隱式類型轉換(導致索引失效,轉換應在參數側)
  9. 優先優化高併發 SQL(破壞力大於低頻大查詢)
  10. 全局視角優化(調整索引勿顧此失彼,所有 SQL 共同受益)

總結

讀懂 EXPLAIN,核心在於關注 type(訪問策略)、key(實際索引)、rows(掃描規模)、Extra(額外開銷)。結合「減少 IO、降低 CPU」兩大目標,針對性調整索引與 SQL 結構,方能寫出經得起高併發考驗的查詢語句。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved