MySQL EXPLAIN 執行計劃深度解析:各欄位含義、Type 類型優劣、Extra 關鍵資訊
EXPLAIN 是 SQL 調優核心工具,展示優化器選擇的存取路徑、聯結順序、索引使用情況。掌握各欄位含義,快速定位效能瓶頸。
實戰範例
EXPLAIN SELECT s.uid, s.username, s.name, f.email, f.mobile, f.phone, f.postalcode, f.address
FROM uchome_space AS s
JOIN uchome_spacefield AS f ON s.uid = f.uid
WHERE s.groupid = 0;
核心欄位詳細說明
| 欄位 | 含義 | 關鍵解讀 |
| id | SELECT 識別符,查詢序號 | 子查詢、UNION 會有多行,id 相同從上往下執行,id 較大優先 |
| select_type | 查詢類型 | SIMPLE(無子查詢/UNION)、PRIMARY(最外層)、SUBQUERY、DERIVED(衍生表)、UNION、UNION RESULT |
| table | 存取的表(或衍生表別名) | 顯示實際存取順序 |
| partitions | 匹配的分區(分區表) | 5.6+ 支援 |
| type | 存取類型(核心指標) | 見下表優劣排序 |
| possible_keys | 可能用到的索引 | 參考用,不代表實際使用 |
| key | 實際使用的索引 | NULL 表示全表掃描 |
| key_len | 使用索引長度(字節) | 推斷聯合索引用了幾個欄位 |
| ref | 與索引比較的列/常數 | const、func、NULL、欄位名 |
| rows | 預估掃描行數 | 越小越好,乘積為總掃描行數估值 |
| filtered | 按條件過濾後剩餘行百分比 | 5.6+,越接近 100 越好 |
| Extra | 額外資訊(關鍵) | 見下表關鍵值 |
Type 存取類型優劣排序(由優到劣)
| Type | 說明 | 典型場景 |
| system | 表僅 1 行(const 特例) | 系統表 |
| const | 主鍵/唯一索引等值查詢,最多 1 行 | WHERE id=1 |
| eq_ref | 唯一索引/主鍵聯結,每行匹配 1 行 | JOIN ... ON pk = pk |
| ref | 非唯一索引等值查詢/聯結 | WHERE idx_col = 'val' |
| ref_or_null | ref + NULL 值優化 | 子查詢優化 |
| index_merge | 多索引合併掃描 | WHERE idx1=1 OR idx2=2 |
| unique_subquery | IN 子查詢主鍵查找 | WHERE id IN (SELECT id FROM...) |
| index_subquery | IN 子查詢非唯一索引 | 同上 |
| range | 索引範圍掃描 | BETWEEN, IN, >, <, >=, <= |
| index | 全索引掃描(僅走索引樹) | SELECT idx_col FROM t |
| ALL | 全表掃描(最差) | 無索引、條件不走索引 |
Extra 關鍵資訊解讀
| Extra 值 | 含義 | 優化方向 |
| Using index | 覆蓋索引,僅讀索引樹不回表 | 優秀,設計覆蓋索引 |
| Using where | Server 層過濾(存儲引擎返回後再篩選) | 正常,但若 type=ALL 需加索引 |
| Using index condition | ICP(Index Condition Pushdown),存儲引擎層過濾 | 5.6+ 優化,減少回表 |
| Using filesort | 檔案排序(需優化) | 加索引消除排序、避免 SELECT * |
| Using temporary | 建立臨時表(需優化) | 優化 GROUP BY/ORDER BY、加索引 |
| Using join buffer | Block Nested Loop Join 使用聯結緩衝 | 小表驅動大表、加索引 |
| Impossible WHERE | WHERE 條件永假 | 檢查條件邏輯 |
| Select tables optimized away | 聚合查詢優化(如 MIN/MAX 走索引) | 優秀 |
實戰分析技巧
- 關注 type:目標達到
ref 以上,避免 ALL、index。
- 檢查 key:是否用上預期索引?
NULL 需加索引或改寫 SQL。
- 估算 rows:各表
rows 相乘為總掃描行數估值,超過 10 萬需優化。
- 消除 Using filesort/temporary:
- ORDER BY 欄位加索引
- GROUP BY 欄位加索引
- 避免 SELECT * 觸發臨時表
- 驅動表原則:MySQL 採用 Nested Loop Join,EXPLAIN 第一行為驅動表。永遠用小結果集驅動大結果集。
- ORDER BY 驅動表欄位 不需臨時表
- ORDER BY 非驅動表欄位 觸發 Using temporary
- 讓優化器自動選 JOIN 類型:寫
FROM t1 JOIN t2 ON t1.id = t2.id 而非指定 LEFT/RIGHT JOIN,除非業務需要外聯結語義。
常見誤區
- 以為
possible_keys 有值就代表用上索引 → 看 key 欄位。
- 忽略
filtered 欄位 → 低百分比表示大量行被過濾,索引選擇性差。
- EXPLAIN 不會執行查詢,
rows 為統計資訊估算,實際可能偏差大 → 配合 ANALYZE TABLE 更新統計。