前言
調用 EXPLAIN 來獲取關於查詢執行計劃的信息與輸出
調用 EXPLAIN
-
使用:在 SELECT 關鍵字之前增加 EXPLAIN
-
每個表在輸出中只有一行,若多表關聯,則輸出多行
- 這裏的表的定義:可以是一個子查詢,一個 UNION 結果
- EXPLAIN 的兩個主要變種
- EXPLAIN EXTENDED
- 服務器 “逆向編譯” 執行計劃爲一個 SELECT 語句(SHOW WARNINGS 後能看到
- 額外增加一個 filtered 列
- EXPLAIN PARTITIONS
- 顯示查詢將訪問的分區
- EXPLAIN EXTENDED
-
EXPLAIN 查詢時,會執行子查詢並將其結果放在一個臨時表中,然後完成外層查詢優化
-
EXPLAIN 返回的只是個近似結果
-
EXPLAIN 相關的限制
-
無法知道觸發器、存儲過程或 UDF 如何影響查詢
-
不支持存儲過程(單可以單獨抽取查詢進行 EXPLAIN
-
無法知道查詢執行中所做的特定優化
-
不會顯示關於查詢的執行計劃的所有信息
-
無法區分具有相同名字的事物
- 內存排序 和 臨時文件 都使用 filesort
- 磁盤上和內存中的臨時表都顯示 Using temporary
-
可能會誤導(對一個有着小 LIMIT 的查詢顯示 全索引掃描
重寫非 SELECT 查詢
-
EXPLAIN 只能解釋 SELECGT 查詢,無法對 INSERT、UPDATE、DELETE 或其他語句做解釋
-
可通過重寫某些非 SELECT 查詢以利用 EXPLAIN
- 轉化成一個等價的訪問所有相同列的 SELECT
- 任何提及的列都必須在 SELECT 列表,關聯子句 或者 WHERE 子句中
-
顯示計劃時,對於寫查詢並沒有“等價”的讀查詢
- 讀只需要找到數據的一份副本並返回
- 寫需要查找並修改其所有副本(消耗更高
EXPLAIN 中的列
-
id 列
-
總是包含一個編碼,標識 SELECT 所屬的行
-
簡單查詢類型
-
複雜查詢類型
- 簡單子查詢
- 派生表
- UNION
-
UNION 結果總是放在一個匿名臨時表中(它的 id 列是 NULL
-
-
select_type 列
- SIMPLE
- 不包括子查詢和 UNION
- PRIMARY
- 查找中存在複雜的子部分,最外層部分標記爲 PRIMARY
- SUBQUERY
- SELECT 列表中的子查詢中的 SELECT
- DERIVED
- FROM 子句的子查詢中的 SELECT(派生表
- UNION
- 在 UNION 中的第二個和隨後的 SELECT 被標記爲 UNION
- UNION RESULT
- 從 UNION 的匿名臨時表檢索結果的 SELECT
- DEPENDENT
- SELECT 依賴與外層查詢中發現的數據
- UNCACHEABLE
- SELECT 中的某些特性阻止結果被緩存於一個 Item_cache 中
- SIMPLE
-
table 列
- 顯示對應行正在訪問哪個表
- MySQL 的查詢執行計劃總是左側深度優先樹
-
type 列
- 顯示了 關聯類型(訪問類型
- 常用的訪問類型(性能依次從最差到最優
- ALL
- 全表掃描(存在例外,例如使用了 LIMIT 或 Extra 列中顯示 Using distinct/not exists
- index
- 類似於全表掃描,只是掃描時按索引次序進行
- 優點:可以避免排序
- 缺點:承擔按索引次序讀取整個表的開銷(意味着按隨機次序訪問行,開銷較大
- range
- 有限制的索引掃描(範圍掃描
- IN ( ) 和 OR 列表使用時均顯示爲 範圍掃描,但兩者其實是相當不同的訪問類型,性能差異較大
- ref
- 索引訪問(索引查找),返回所有匹配某個單個值的行
- 使用場景:使用非唯一索引時 或 唯一索引的非唯一性前綴時
- ref_or_null(變體):MySQL 必須在初次查找的結果裏進行第二次查找以找出 NULL 條目
- eq_ref
- 最多隻返回一條符合條件的記錄
- 使用場景:使用主鍵 或 唯一索引時
- const ,system
- MySQL 能對查詢的某部分進行優化並將其轉換成一個常量時
- NULL
- MySQL 能再優化階段分解查詢語句,在執行階段甚至用不着再訪問表或者索引
- ALL
-
possible_keys 列
- 顯示查詢可能使用哪些索引
-
key 列
- 顯示 MySQL 決定採用哪個索引來優化對該表的訪問(基於最小化查詢成本
- 該索引可能不存在 possible_keys 列中(可能選擇了一個覆蓋索引,哪怕沒有 WHERE 子句
-
key_len 列
- 顯示 MySQL 在索引裏使用的字節數(具體使用到的該索引上的某些列
- key_len 通過查找表的定義而被計算出,而不是表中的數據
-
ref 列
- 顯示在 key 列記錄的索引中查找值所用的列或常量
-
rows 列
- 顯示 MySQL 估計爲了找到所需要的行而要讀取的行數(嵌套循環管理計劃裏的嵌套數目
- 該數字只是 MySQL 認爲它要檢查的行數,而不是結果集裏的行數
-
filtered 列
- 使用 EXPLAIN EXTEND 時纔會出現
- 顯示 針對表裏符合某個條件的記錄數的百分比所做的一個悲觀估算
- 只有在使用 ALL、index、range 和 index_merge 訪問時纔會用到這一估算
- Extra 列
- 顯示不適合在其他列顯示的額外信息
- 常見重要的值
- Using index(覆蓋索引
- Using where(Mysql 服務器將在存儲引擎檢索後再進行過濾
- Using temporary(對查詢結果排序時會使用一個臨時表
- Using filesort(對結果使用一個外部索引排序,詳情請看:《高性能 MySQL》查詢性能優化
- Range checked for each record(沒有好用的索引,新索引將在聯接的每一行上重新估算
MySQL 5.6 中的改進
- 能對類似於 UPDATE、INSERT等的查詢進行解釋
- 對查詢優化和執行引擎的一系列改進
- 允許匿名的臨時表儘可能晚地被具體化
- 可直接解釋帶子查詢的查詢語句,而不需要先實際地執行子查詢
- 增加優化跟蹤功能的方式改進優化器