前言
- 本文中MySQL版本:5.7.10
- MySQL 5.7官方參考手冊:EXPLAIN Output Format
Explain輸出字段
id列
此列總是包含一個編號,可以簡單理解爲SELECT子句執行或者表的讀取順序,對於id號相同的查詢按序從上到下執行,對於id號不同的查詢按id號從大到小的順序執行。
id列的編號從1開始,若沒有子查詢SUBQUERY或者聯合查詢UNION,則Explain每一行輸出的id列都爲1;如果存在子查詢則內層的子查詢的對應id順序增加,代表當前所處的查詢層次;如果存在聯合查詢UNION,則對應臨時表的id列爲NULL。
select_type列
主要代表當前子句查詢的類型,主要用於區別普通查詢、聯合查詢、子查詢等複雜的查詢。常見值主要有6個:
1. SIMPLE
表示當前查詢爲最簡單的查詢,不包含任何子查詢SUBQUERY和聯合查詢UNION
2. PRIMARY
如果查詢中包含任何複雜的部分,則最外層部分的查詢過程被標記爲PRIMARY
3. SUBQUERY
不在FROM子句中的複雜子查詢(如SELECT子句、WHERE子句等)都會被標記爲SUBQUERY
4. DERIVED
DERIVED值用來表示包含在FROM子句中的複雜子查詢,MySQL會遞歸執行這些子查詢,並將結果放置在臨時表中
5. UNION
對於聯合查詢UNION中,第二個及之後的SELECT查詢都會被標記爲UNION。如果UNION查詢被FROM子句中的子查詢包含,那麼UNION查詢中的第一個SELECT語句會被標記爲DERIVED
6. UNION RESULT
用來從UNION的匿名臨時表中檢索結果的SELECT被標記爲UNION RESULT
除了這些值外,SUBQUERY和UNION還可以被標記爲DEPENDENT和UNCACHEABLE。DEPENDENT表明當前的子查詢爲相關子查詢,當前查詢依賴於外部子查詢中檢索到的數據;UNCACHEABLE表明SELECT中的某些特性阻止結果被緩存於一個Item_cache中。
table列
顯示當前查詢過程中訪問的表
partitions列
表明當前查詢過程中,查詢過的記錄來自於當前表的哪些分區。如果爲NULL,則表示當前表未分區
type列
表示對當前表的訪問類型,換言之就是MySQL決定如何查詢表中的行記錄。下面是一些常見值,依次從最優到最差。
1. system
當被查詢的表中只有一行記錄時(等價於系統表),此表的訪問類型會被標記爲system
2. const
若當前查詢中,被查詢表中最多隻有唯一匹配行,匹配條件爲常量時,當前訪問類型會被標記爲const,MySQL會將當前查詢的結果直接優化成一個常量,常出現在對主鍵(Primary Key)或者唯一性索引(Unique Key)進行常量匹配查詢時。例如,當對錶中的某個主鍵或者唯一性索引中包含的所有字段,通過where子句進行常量匹配時,因爲是通過索引進行唯一匹配,查詢非常快,MySQL會直接將查詢結果視爲常量
3. eq_ref
此訪問類型代表了唯一性索引掃描,同時代表當前查詢過程返回的是索引字段匹配某單個值的行記錄。使用這種索引查找,MySQL知道最多隻會返回一條符合查找條件的行記錄,這種訪問類型常見於使用多個值對主鍵索引或者唯一性索引字段進行常量匹配時。
4. ref
此訪問類型代表了非唯一性索引掃描,與eq_ref
相對,代表當前查詢過程是通過非唯一性索引進行表的行記錄查詢,返回的是索引字段匹配某單個值的行記錄,可能會存在多個匹配行,此單個匹配值可以是常量,也可以是前一個查詢結果。此類訪問類型只會出現在,對非唯一性索引或者唯一性索引的非唯一性前綴進行單值匹配時。
5. range
此訪問類型表示使用索引來檢索指定範圍的行記錄。常見於對錶中某個索引(不論是唯一性還是非唯一性)進行行記錄檢索時,使用多個值進行索引字段的匹配查詢,如使用BETWEEN、>、<、IN、OR等。索引字段的範圍查詢(type=range)要優於索引掃描(type=index),因爲範圍查詢要遍歷每一個索引節點,而範圍查詢只需要遍歷部分索引節點即可。
注意:當對非唯一性索引進行範圍查詢時候,若此查詢需要掃描記錄數超過一定數量(大約爲全表記錄數的20%),則MySQL優化器不再使用索引進行範圍查詢(type=range),而是直接進行全表掃描(type=ALL)
6. index
此訪問類型表示當前查詢是按照某個索引的順序進行全表掃描。其主要優點在於按照某個或者某些字段的索引順序進行掃描時,若同時需要對這些字段進行排序,則可以省略排序過程(因爲索引自身有序),這也是使用索引優化排序過程的關鍵所在;缺點在於,如果當前索引不是覆蓋索引(covering index),即Extra
列中沒有顯示Using index
值時,基於索引順序檢索行記錄時,必定會產生磁盤隨機I/O(因爲行記錄是按照主鍵或RowID排序的),進而導致查詢效率十分低下。
7. ALL
此訪問類型表示當前查詢的訪問類型爲全表掃描,即按照表中行記錄順序進行全表掃描。此訪問類型在所有訪問類型中查詢效率最差,一般若出現此訪問類型,則表示當前查詢過程急需優化,通常是對特定字段建立索引來避免全表掃描。當然實際過程中,有時也難以避免全表掃描。
possible_keys列
表示當前表中與當前查詢相關的索引,即MySQL可以通過其檢索行記錄的索引。若possible_keys
爲NULL,也並不代表當前表中沒有索引,只是代表當前查詢中沒有可以使用的索引。
key列
表示當前查詢過程中實際使用的索引。注意:當使用覆蓋索引時,key
中指定的索引,可能並不會在possible_keys
中列出。
key_len列
表示當前查詢過程中所使用的索引的字節長度,如果key
列爲NULL(表明未使用索引),則key_len
列同樣爲NULL。
ref列
表示當前查詢過程中進行索引匹配時所使用的字段或者常量。若爲const
則表明在進行索引查找時,使用的是某個常量值進行匹配;若爲某個表的字段,則表明在進行索引查找時,使用的是其字段對應值進行匹配。
rows列
表示MySQL認爲執行當前SQL查詢所需要讀取的行記錄數。對於存儲引擎爲InnoDB的表而言,這一列的值只是個估計值,並不一定準確。
filtered列
表示經過當前查詢條件過濾之後剩餘記錄數佔已讀取記錄數的百分比,是一個悲觀的估計值。此列值的範圍爲0~100,若等於100,則表明未發生過濾,越小則表明過濾的數據行越多。rows*filtered/100
的值爲當前查詢結果的實際行記錄數的一個估計值。
Extra列
此列記錄有MySQL處理當前查詢的一些重要的額外信息,可以有多個值。其中常見值的解釋如下:
1. Using filesort
此值表明MySQL必須通過額外的排序操作來滿足查詢ORDER BY子句中的排序條件。通常出現於ORDER BY排序條件中的字段未創建索引的情況
2. Using index
此值表明MySQL將使用覆蓋索引(Covering Index)來獲取查詢字段數據,避免訪問具體的數據行。這是索引優化查詢的方式之一。注意:所謂覆蓋索引(Covering Index)簡單理解就是查詢字段的值被索引的字段完全覆蓋,可以直接通過檢索索引對應數據結構就可以獲取查詢字段的值
3. Using Index Condition
此值表明MySQL執行當前查詢過程時使用了索引下推(ICP,Index Condition Pushdown)優化,即在掃描索引時直接判斷某個行記錄是否需要讀取,而不是通過直接去讀取具體的數據行後進行過濾,儘可能減少隨機I/O次數。通常發生在對某個索引進行掃描時,過濾條件對應的字段同屬於此索引中的某個字段的查詢過程中。
4. Using join buffer (Block Nested Loop)
此值表明MySQL在執行當前查詢過程中使用了BNL聯接算法,主要是針對聯接條件外部表對應字段未建立索引的情況。即使用join buffer(聯接緩衝區)批量緩存外部表中的相關列,一次性對內部表的每條記錄進行多次匹配,進而大大減少嵌套查詢中內部表的掃描次數。
注意:嵌套查詢中外部表不一定是外部查詢的表,也有可能是子查詢對應的表
5. Using join buffer (Batched Key Access)
此值表明MySQL在執行當前查詢過程中使用了BKA聯接算法,主要針對聯接條件中外部表對應字段使用的是輔助索引(二級索引)且查詢字段未被此索引覆蓋的情況。和BNL算法類似,同樣先使用join buffer(聯接緩衝區)批量緩存外部表中的相關列,進而減少內部表的掃描次數,但是在獲取查詢字段對應的具體數據時並不是按照聯接字段的輔助索引(二級索引)的順序獲取,而是通過批量地將索引鍵值發送給Multi-Range Read(MRR)接口,MRR會將輔助索引按照對應的RowID進行排序,然後訪問對應的具體數據行,最後將結果集返回給客戶端。
6. Using MRR
此值表明MySQL在執行當前查詢過程中使用了Multi-Range Read(MRR)優化。即將輔助索引進行緩存,並在緩存中將其按照RowID進行排序,最終根據RowID的順序來訪問具體的數據行。MRR優化的主要作用就是通過按照RowID的順序訪問具體的數據行,儘量減少隨機I/O的次數,主要適用於range,ref,eq_ref類型的查詢。
7. Using temporary
此值表明MySQL爲了處理當前查詢過程,需要創建臨時表來保存結果。常見於使用GROUP BY、ORDER BY、或UNION等查詢語句中。
8. Using where
此值表明MySQL服務器在存儲引擎檢索到查詢字段對應的最終行記錄後進行了過濾。注意:並不是所有的帶where子句的查詢的Extra列中都會標記爲“Using where”,如對某個索引的最左前綴進行where等值常量匹配時,則不會被標記爲“Using where”。
參考資料
MySQL 5.7 官方參考手冊:EXPLAIN Output Format
《高性能MySQL(第三版)》附錄D EXPLAIN
《MySQL技術內幕:InnoDB存儲引擎(第2版)》5.6.6Multi-Range Read優化、5.6.7Index Condition Pushdown(ICP)優化
《MySQL技術內幕:SQL編程》5.5.2Block Nested-Loops Join算法、5.5.3Batched Key Access Join算法