`EXPLAIN` 是 SQL 調優的「聽診器」。看懂執行計劃,等於看懂了 MySQL 如何思考。本文系統講解各列含義、常見類型、優化判斷依據。
CREATE TABLE t1 (
c1 INT PRIMARY KEY,
c2 VARCHAR(128), KEY ind_c2(c2),
c3 VARCHAR(64),
c4 INT, KEY ind_c4(c4)
) ENGINE=InnoDB;
CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 VARCHAR(128), KEY ind_c2(c2), c3 VARCHAR(64), c4 INT) ENGINE=InnoDB;
CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 VARCHAR(128), KEY ind_c2(c2), c3 VARCHAR(64), c4 INT) ENGINE=InnoDB;
| 類型 | 含義 |
|---|---|
| SIMPLE | 無子查詢/UNION 的簡單查詢 |
| PRIMARY | 包含子查詢的最外層查詢 |
| SUBQUERY | SELECT/WHERE 列表中的子查詢 |
| DERIVED | FROM 列表中的子查詢 (衍生表) |
| UNION | UNION 中第二個及以後的 SELECT |
| UNION RESULT | UNION 合併結果的虛擬表 |
| 類型 | 含義 | 典型場景 | 性能 |
|---|---|---|---|
| system/const | 常量級訪問,最多 1 行 | PK/UK 查詢 `WHERE id=1` | ⭐⭐⭐⭐⭐ 極快 |
| eq_ref | 唯一索引掃描,JOIN 關聯 | PK/UK JOIN `ON t1.id=t2.id` | ⭐⭐⭐⭐ 優 |
| ref | 非唯一索引掃描 | 普通索引 `WHERE idx_col=val` | ⭐⭐⭐ 良 |
| range | 索引範圍掃描 | `BETWEEN`, `>`, `<`, `IN`, `LIKE 'prefix%'` | ⭐⭐ 可接受 |
| index | 全索引掃描 | 覆蓋索引 `SELECT idx_col FROM t` | ⭐ 較慢 |
| ALL | 全表掃描 | 無索引、索引失效 | ❌ 差 |
**目標**:核心查詢至少達到 `ref`,核心 JOIN 達到 `eq_ref`,杜絕 `ALL`。
顯示哪個表的哪個列/常量被用於索引查找。如 `const`、`t1.c1`、`func`。
基於統計信息估算,**僅供參考**,實際可能相差數量級。關注數量級:10 < 1000 < 100000。
| 信息 | 含義 | 優化方向 |
|---|---|---|
| Using index | 覆蓋索引,僅掃描索引不回表 | ✅ 極佳,繼續保持 |
| Using where | Server 層過濾 (存儲引擎返回後再過濾) | ⚠️ 檢查能否下推到引擎 (ICP) |
| Using index condition (ICP) | 索引條件下推,引擎層過濾 | ✅ 好,減少回表 |
| Using temporary | 創建臨時表 (通常 GROUP BY/ORDER BY 異字段) | ❌ 優化索引/調整 SQL 避免 |
| Using filesort | 文件排序 (無索引排序/排序字段不匹配) | ❌ 建立匹配 ORDER BY 的索引 |
| Impossible WHERE | WHERE 條件永假 | ✅ 優化器直接返回空 |
| Select tables optimized away | 聚合查詢優化 (如 MIN/MAX 走索引) | ✅ 極佳 |
EXPLAIN SELECT * FROM t1 WHERE c3 = 'abc';
-- type=ALL, key=NULL, rows=全表行數, Extra=Using where
-- ✅ 優化:ALTER TABLE t1 ADD INDEX idx_c3(c3); → type=ref
EXPLAIN SELECT * FROM t1 WHERE c2='x' ORDER BY c3;
-- type=ref (用 ind_c2), Extra=Using where; Using filesort
-- ✅ 優化:ALTER TABLE t1 ADD INDEX idx_c2_c3(c2, c3); → Extra=Using index condition (無 filesort)
EXPLAIN SELECT c1, c2 FROM t1 WHERE c2='x';
-- type=ref, key=ind_c2, Extra=Using index (覆蓋索引,無回表)
-- ✅ 如果 SELECT c1,c2,c3 → 非覆蓋,需回表,考慮加 c3 到索引 (idx_c2_c3) 但權衡寫入開銷
EXPLAIN SELECT * FROM t1 JOIN t2 ON t1.c1=t2.c1 WHERE t1.c2='x';
-- t1: type=ref, key=ind_c2
-- t2: type=eq_ref, key=PRIMARY (PK JOIN 最優)
-- ✅ 驅動表 (t1) 有過濾索引,被驅動表 (t2) 用 PK 關聯,完美
讀懂 `EXPLAIN` 核心在於:**看 type 定性能、看 key 定索引、看 Extra 定優化方向**。熟練掌握各列含義,結合業務 SQL 模式,才能精準定位瓶頸、實施有效索引優化。