MySQL EXPLAIN 命令: 檢視查詢執行計劃
MySQL 的 EXPLAIN 命令可以檢視SELECT語句的執行的計劃,是 MySQL 查詢優化的必備工具。
通過執行計劃可以瞭解查詢方式、索引使用情況、需要掃描的資料量以及是否需要臨時表或排序操作等資訊。
我們需要分析執行計劃對查詢進行有的放矢的優化。
需要注意:
- EXPLAIN不考慮觸發器、儲存過程或使用者自定義函式對查詢的影響
- EXPLAIN不考慮快取
- EXPLAIN只能分析執行計劃,不能顯示儲存引擎在執行查詢過程中進行的操作
- 部分統計資訊是估算的,並非精確值
本文基於 MySQL 5.6 版本。
EXPLAIN SELECT * FROM `user` JOIN `post` ON `user`.id = `post`.uid WHERE user.`created_at` < '2018-10-01 00:00:00' AND `post`.status = 1;
結果:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | user | range | PRIMARY,idx_created_at | idx_created_at | 7 | null | 19440 | Using index condition; Using where; Using temporary; Using filesort |
1 | SIMPLE | post | ref | idx_uid,idx_status | idx_uid | 8 | user.id | 1 | Using where |
EXPLAIN 的行數為查詢涉及的表數, 結果各列的含義為:
- id: 查詢的唯一標識
- select_type: 查詢的型別
- table: 查詢的表, 可能是資料庫中的表/檢視,也可能是 FROM 中的子查詢
- type: 搜尋資料的方法
- possible_keys: 可能使用的索引
- key: 最終決定要使用的key
- key_len: 查詢索引使用的位元組數。通常越少越好
- ref: 查詢的列或常量
- rows: 需要掃描的行數,估計值。通常越少越好
- extra: 額外的資訊
select type
select_type 可能的值有:
- SIMPLE: 簡單查詢,不包含子查詢和union
- PRIMRARY: 包含子查詢時的最外層查詢; 使用union時的第一個查詢
- UNION: 包含union的查詢中非第一個查詢
- DEPENDENT UNION: 與 UNION 相同,但依賴外層查詢的結果
- SUBQUERY: 子查詢
- DEPENDENT SUBQUERY: 依賴外層查詢的子查詢
- DERIVED: 用於 FROM 中的子查詢
下面給出幾個示例:
EXPLAIN SELECT * FROM post WHERE uid = (
SELECT id FROM user WHERE name = "finley"
);
id | select_type | table |
---|---|---|
1 | PRIMARY | post |
2 | SUBQUERY | user |
DEPENDENT SUBQUERY:
EXPLAIN SELECT * FROM post WHERE uid = (
SELECT id FROM user WHERE name = "finley" AND post.uid=user.id
);
id | select_type | table |
---|---|---|
1 | PRIMARY | post |
2 | DEPENDENT SUBQUERY | user |
type
type 欄位描述了查詢的方式,從好到壞為:
- null: 不需要訪問索引和表即可完成, 示例:
SELECT 1;
const: 表中僅有一行匹配,在分解查詢計劃時直接將其讀出作為常量使用。system 是 const 型別的特例。 示例:
SELECT id FROM user WHERE name = "hdt3213";
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user const uni_name uni_name 258 const 1 Using index
UNIQUE KEY uni_name (name) ON user
eq_ref: 使用 PRIMARY KEY 或 UNIQUE KEY 進行關聯查詢。 示例:
SELECT * FROM post JOIN user ON post.uid = user.id WHERE user.gender = 'M';
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE post ALL idx_uid 0 0 0 57796 null 1 SIMPLE user eq_ref PRIMARY PRIMARY 8 post.uid 1 Using where ref: 使用允許重複的索引進行查詢 示例:
SELECT * FROM user WHERE phone='12345678901';
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user ref idx_phone idx_phone 259 const 1 Using index condition range: 使用索引進行範圍查詢: 示例:
SELECT * FROM user WHERE age>18;
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user ref idx_age idx_age 259 const 1 null index: 在索引上進行順序掃描。常見於在多列索引中未使用最左列進行查詢。 示例:
SELECT * FROM user WHERE last_name='smith'
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE user ref idx_full_name idx_full_name 259 const 1 Using where all: 掃描全表,最壞的情況
extra
extra 列顯示了查詢過程中需要執行的其它操作,有些情況應盡力避免。
- using filesort: 查詢時執行了排序操作而無法使用索引排序。雖然名稱為'file'但操作可能是在記憶體中執行的,取決是否有足夠的記憶體進行排序。 應儘量避免這種filesort出現。
- using temporary: 使用臨時表儲存中間結果,常見於ORDER BY和GROUP BY語句中。臨時表可能在記憶體中也可能在硬碟中,應儘量避免這種操作出現。
- using index: 索引中包含查詢的所有列(覆蓋索引)不需要查詢資料表。可以加快查詢速度。
- using index condition: 索引條件推送(MySQL 5.6 新特性),伺服器層將不能直接使用索引的查詢條件推送給儲存引擎,從而避免在伺服器層進行過濾。
- using where: 伺服器層對儲存引擎返回的資料進行了過濾
- distinct: 優化distinct操作,查詢到匹配的資料後停止繼續搜尋