explain 介紹
explain顯示了MySQL如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優化的查詢語句。簡單講,它的作用就是分析查詢性能。explain + 查詢SQL - 用于顯示SQL執行信息參數,根據參考信息可以進行SQL優化
示例:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | PRIMARY | | ALL | NULL | NULL | NULL | NULL | 9 | NULL |
| 2 | DERIVED | tb1 | range | PRIMARY | PRIMARY | 8 | NULL | 9 | Using where |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
id
查詢順序標識,每個 SELECT 都會自動分配一個唯一的標識符。列數字越大越先執行,如果數字一樣大,那么就從上往下依次執行,id列為null的就表示這是一個結果集,不需要使用它來進行查詢,例如使用union連接可能為null
select_type 查詢類型
- simple:表示不需要union操作或者不包含子查詢的簡單select查詢。有連接查詢時,外層的查詢為simple,且只有一個
- primary:一個需要union操作或者含有子查詢的select,位于最外層的單位查詢的select_type即為primary。且只有一個
- union:union連接的兩個select查詢,第一個查詢是dervied派生表,除了第一個表外,第二個以后的表select_type都是union
- dependent union:與union一樣,出現在union 或union all語句中,但是這個查詢要受到外部查詢的影響
- union result:包含union的結果集,在union和union all語句中,因為它不需要參與查詢,所以id字段為null
- subquery:除了from字句中包含的子查詢外,其他地方出現的子查詢都可能是subquery
- dependent subquery:與dependent union類似,表示這個subquery的查詢要受到外部表查詢的影響
- derived:from字句中出現的子查詢,也叫做派生表,其他數據庫中可能叫做內聯視圖或嵌套select
? ? ...
table
顯示的查詢表名,如果查詢使用了別名,那么這里顯示的是別名,如果不涉及對數據表的操作,那么這顯示為null,如果顯示為尖括號括起來的<derived N>就表示這個是臨時表,后邊的N就是執行計劃中的id,表示結果來自于這個查詢產生。如果是尖括號括起來的<union M,N>,與<derived N>類似,也是一個臨時表,表示這個結果來自于union查詢的id為M,N的結果集
type
依次從好到差:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,all,除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引
- system:表中只有一行數據或者是空表,且只能用于myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index,這是const聯接類型的一個特例。select * from (select nid from tb1 where nid = 1) as A;
- const:使用唯一索引或者主鍵,返回記錄一定是1行記錄的等值where條件時,通常type是const。其他數據庫也叫做唯一索引掃描select nid from tb1 where nid = 2 ;
- eq_ref:出現在要連接過個表的查詢計劃中,驅動表只返回一行數據,且這行數據是第二個表的主鍵或者唯一索引,且必須為not null,唯一索引和主鍵是多列時,只有所有的列都用作比較時才會出現eq_ref。select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
- ref:根據索引查找一個或多個值。此類型通常出現在多表的 join 查詢, 針對于非唯一或非主鍵索引, 或者是使用了 最左前綴 規則索引的查詢。不像 eq_ref 那樣要求連接順序,也沒有主鍵和唯一索引的要求,只要使用相等條件檢索時就可能出現,常見與輔助索引的等值查找。或者多列主鍵、唯一索引中,使用第一個列之外的列作為等值查找也會出現,總之,返回數據不唯一的等值查找就可能出現。
- fulltext:全文索引檢索,要注意,全文索引的優先級很高,若全文索引和普通索引同時存在時,mysql不管代價,優先選擇使用全文索引
- ref_or_null:與ref方法類似,只是增加了null值的比較。實際用的不多。
- unique_subquery:用于where中的in形式子查詢,子查詢返回不重復值唯一值
- index_subquery:用于in形式子查詢使用到了輔助索引或者in常數列表,子查詢可能返回重復值,可以使用索引將子查詢去重。
- range:表示使用索引范圍查詢, 通過索引字段范圍獲取表中部分數據記錄. 這個類型通常出現在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中當 type 是 range 時, 那么 EXPLAIN 輸出的 ref 字段為 NULL, 并且 key_len 字段是此次查詢中使用到的索引的最長的那個。
- index_merge:表示查詢使用了兩個以上的索引,最后取交集或者并集,常見and ,or的條件使用了不同的索引,官方排序這個在ref_or_null之后,但是實際上由于要讀取所個索引,性能可能大部分時間都不如range
- index:表示全索引掃描(full index scan), 和 ALL 類型類似, 只不過 ALL 類型是全表掃描, 而 index 類型則僅僅掃描所有的索引, 而不掃描數據.index 類型通常出現在: 所要查詢的數據直接在索引樹中就可以獲取到, 而不需要掃描數據. 當是這種情況時, Extra 字段 會顯示 Using index.比如, 我們查詢的 name 字段恰好是一個索引, 因此我們直接從索引中獲取數據就可以滿足查詢的需求了, 而不需要查詢表中的數據. 因此這樣的情況下, type 的值是 index, 并且 Extra 的值是 Using index.
- all:這個就是全表掃描數據文件,然后再在server層進行過濾返回符合要求的記錄。這個類型的查詢是性能最差的查詢之一,最不建議使用
possible_keys ?
查詢可能使用到的索引都會在這里列出來
key
查詢真正使用到的索引,select_type 為 index_merge 時,這里可能出現兩個以上的索引,其他的select_type這里只會出現一個
key_len ?
用于處理查詢的索引長度,如果是單列索引,那就整個索引長度算進去,如果是多列索引,那么查詢不一定都能使用到所有的列,具體使用到了多少個列的索引,這里就會計算進去,沒有使用到的列,這里不會計算進去。留意下這個列的值,算一下你的多列索引總長度就知道有沒有使用到所有的列了。要注意,mysql的ICP特性使用到的索引不會計入其中。另外,key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。
ref
如果是使用的常數等值查詢,這里會顯示const,如果是連接查詢,被驅動表的執行計劃這里會顯示驅動表的關聯字段,如果是條件使用了表達式或者函數,或者條件列發生了內部隱式轉換,這里可能顯示為func
rows ?
mysql估計為了找到所需的行而要讀取的行數 ------ 只是預估值
extra
這個列可以顯示的信息非常多,有幾十種,常用的有:
- distinct:在select部分使用了distinc關鍵字
- no tables used:不帶from字句的查詢或者From dual查詢
- using filesort:排序時無法使用到索引時,就會出現這個。常見于order by和group by語句中
- using index:查詢時不需要回表查詢,直接通過覆蓋索引就可以獲取查詢的數據。
- using join buffer(block nested loop),using join buffer(batched key accss):5.6.x之后的版本優化關聯查詢的BNL,BKA特性。主要是減少內表的循環數量以及比較順序地掃描查詢。
- using intersect:表示使用and的各個索引的條件時,該信息表示是從處理結果獲取交集
- using union:表示使用or連接各個使用索引的條件時,該信息表示從處理結果獲取并集
- using sort_union和using sort_intersection:與前面兩個對應的類似,只是他們是出現在用and和or查詢信息量大時,先查詢主鍵,然后進行排序合并后,才能讀取記錄并返回。
- using temporary:表示使用了臨時表存儲中間結果。臨時表可以是內存臨時表和磁盤臨時表,執行計劃中看不出來,需要查看status變量,used_tmp_table,used_tmp_disk_table才能看出來。
- using where:表示存儲引擎返回的記錄并不是所有的都滿足查詢條件,需要在server層進行過濾。查詢條件中分為限制條件和檢查條件,5.6之前,存儲引擎只能根據限制條件掃描數據并返回,然后server層根據檢查條件進行過濾再返回真正符合查詢的數據。5.6.x之后支持ICP特性,可以把檢查條件也下推到存儲引擎層,不符合檢查條件和限制條件的數據,直接不讀取,這樣就大大減少了存儲引擎掃描的記錄數量。extra列顯示using index condition。mysql服務器將在存儲引擎檢索行后再進行過濾,許多where條件里涉及索引中的列,當(并且如果)它讀取索引時,就能被存儲引擎檢驗,因此不是所有帶where子句的查詢都會顯示“Using where”。有時“Using where”的出現就是一個暗示:查詢可受益于不同的索引。
- firstmatch(tb_name):5.6.x開始引入的優化子查詢的新特性之一,常見于where字句含有in()類型的子查詢。如果內表的數據量比較大,就可能出現這個
- loosescan(m..n):5.6.x之后引入的優化子查詢的新特性之一,在in()類型的子查詢中,子查詢返回的可能有重復記錄時,就可能出現這個
filtered
使用explain extended時會出現這個列,5.7之后的版本默認就有這個字段,不需要使用explain extended了。這個字段表示存儲引擎返回的數據在server層過濾后,剩下多少滿足查詢的記錄數量的比例,注意是百分比,不是具體記錄數。
id | SELECT識別符。這是SELECT的查詢序列號 |
select_type | SELECT類型,可以為以下任何一種: SIMPLE:簡單SELECT(不使用UNION或子查詢) PRIMARY:最外面的SELECT UNION:UNION中的第二個或后面的SELECT語句 DEPENDENT UNION:UNION中的第二個或后面的SELECT語句,取決于外面的查詢 UNION RESULT:UNION 的結果 SUBQUERY:子查詢中的第一個SELECT DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決于外面的查詢 DERIVED:導出表的SELECT(FROM子句的子查詢) |
table | 輸出的行所引用的表 |
type | 聯接類型。下面給出各種聯接類型,按照從最佳類型到最壞類型進行排序: system:表僅有一行(=系統表)。這是const聯接類型的一個特例。 const:表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩余部分認為是常數。const表很快,因為它們只讀取一次! eq_ref:對于每個來自于前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。 ref:對于每個來自于前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。 ref_or_null:該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。 index_merge:該聯接類型表示使用了索引合并優化方法。 unique_subquery:該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。 index_subquery:該聯接類型類似于unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr) range:只檢索給定范圍的行,使用一個索引來選擇行。 index:該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。 ALL:對于每個來自于先前的表的行組合,進行完整的表掃描。 |
possible_keys | 指出MySQL能使用哪個索引在該表中找到行 |
key | 顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。 |
key_len | 顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。 |
ref | 顯示使用哪個列或常數與key一起從表中選擇行。 |
rows | 顯示MySQL認為它執行查詢時必須檢查的行數。多行之間的數據相乘可以估算要處理的行數。 |
filtered | 顯示了通過條件過濾出的行數的百分比估計值。 |
Extra | 該列包含MySQL解決查詢的詳細信息 Distinct:MySQL發現第1個匹配行后,停止為當前的行組合搜索更多的行。 Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行后,不再為前面的的行組合在該表內檢查更多的行。 range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。 Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。 Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。 Using temporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。 Using where:WHERE 子句用于限制哪一個行匹配下一個表或發送到客戶。 Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合并索引掃描。 Using index for group-by:類似于訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查 詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。 |