1. 程式人生 > >MySQL EXPLAIN 命令: 檢視查詢執行計劃

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 欄位描述了查詢的方式,從好到壞為:

  1. null: 不需要訪問索引和表即可完成, 示例: SELECT 1;
  2. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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操作,查詢到匹配的資料後停止繼續搜尋