使用EXPLAIN加上SELECT語句能夠獲取優化器的查詢執行計劃數組
MySQL會在查詢上設置一個標記,當執行查詢時,這個標記會返回關於在執行計劃中每一步的信息,而不是執行它。它會返回一行或多行信息,一個表示一張表,顯示出執行計劃中的每一部分和執行的次序。服務器
複雜的查詢如from子句中包含查詢,select列中也包含查詢,則執行順序爲,先執行外層查詢,再執行from子句中的子查詢,最後執行select列表中的子查詢優化
下面是查詢結果的一個示例(爲了方便查看作成了表格):排序
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
1 | SIMPLE | scores | const | PRIMARY | PRIMARY | 8 | const | 1 |
1 row in set索引
實際上EXPLAIN後的SELECT語句的from子句包含子查詢時,MySQL會執行子查詢,再將結果放在一個臨時表中,而後完成外層查詢優化。內存
其實EXPLAIN只是一個近似的結果,有時甚至會相差甚遠,下面是EXPALIN的一些限制io
一、EXPLAIN不會告訴你觸發器、存儲過程或UDF會如何影響查詢的table
二、它並不支持存儲過程。儘管能夠手動抽取查詢並單獨地對齊進行EXPLAIN操做class
三、它並不會告訴你MySQL在查詢執行中所作的特定優化file
四、它並不會顯示關於查詢的執行計劃的全部信息
五、它並不區分具備相同名字的事物,例如對內存排序和臨時文件排序都使用filesort,而且對於磁盤上和內存中的臨時表都顯示Using temporary
六、可能會誤導。例如,對一個有着很小LIMIT的查詢顯示全索引掃描,5.1及以後的版本中EXPLAIN關於檢查的行數會顯示更精確的信息
EXPLAIN中的列
id列
每一列的編號,若是有子查詢和JOIN時,會顯示多行,id按其在原始SQL語句中的順序編號
select_type列
顯示對應行的查詢是簡單仍是複雜,複雜類型分爲三大類:簡單子查詢、所謂的派生表(在from子句中的子查詢)、UNION查詢,下面是可能的值
SIMPLE 意味着查詢不包含子查詢和UNION
PRIMARY 查詢中有複雜部分,最外層的查詢標記爲PRIMARY
SUBQUERY 包含不在FROM子句中子查詢(在SELECT列表中的子查詢)
DERIVED 表示FROM子句有SELECT子查詢,MySQL會先執行子查詢並將結果放在臨時表中
UNION UNION關鍵字後及之後的SELECT標記爲UNION,UNION前的查詢標記爲PRIMARY
UNION RESULT 用來從包含UNION的匿名臨時表檢索結果的SELECT標記爲UNION RESULT
table列
這一列顯示了對應行正在訪問哪一個表,從這一列從上往下能夠觀察到MySQL的關聯優化器爲查詢選擇的關聯順序。
包含多個JOIN的SELECT,從下往上先執行JOIN中的表
<derivedN> FROM子句有子查詢時,N表示子查詢的id,N執行EXPLAIN輸出中的後面一行(先前引用)
<unionid1,id2> UNION RESULT的table列,id表示參與UNION的行的列表
type列
顯示訪問類型,即MySQL決定如何查找表中的行,下面是最重要的訪問方法,依次從最差到最優
ALL
全表掃描,意味着MySQL必須掃描整張表,從頭至尾去找到須要的行。可是在查詢中使用了LIMIT或者在Extra列顯示Using distinct/not exists時
type列也會顯示ALL
index
也是全表掃描,只是MySQL掃描表時按照索引次序掃描而不是逐行掃描。它最大的優勢是避免了排序,最大的缺點是要按索引次序讀取整個表
(使用索引掃描來排序,每掃描一條記錄就回表查詢一次對應的行)
range
範圍掃描,即一個有限制的索引掃描,始於索引中的某一點,返回匹配區域內的行。比全表掃描好些,它意味着沒必要遍歷所有索引中的節點。
ref
這是一種索引訪問(索引查找),它返回全部匹配某個單個值的行,可能有多個符合兒條件的行。所以它是查找和掃描的混合體,此類索引訪問只有當使用
非惟一性索引或者惟一性索引的非惟一性前綴時纔會發生。稱做ref由於索引要跟某個參考值比較,ref能夠用於使用=或<=>操做符的帶索引的列。
ref_or_null是ref之上的一個變體,意味着MySQL必須在初次查找的結果裏進行第二次查找以找出NULL條目
eq_ref
使用這種索引,MySQL知道最多隻返回一條符合條件的記錄。這種訪問方法能夠在MySQL使用主鍵或者惟一性索引查找時看到。
const,system
當MySQL能對查詢的某部分進行優化並將其轉換成一個常量時,就會返回此訪問類型。如查找某一行的主鍵值where後的條件就是主鍵,MySQL就能把這個
查詢轉換爲一個常量,而後就能夠高效地將表從聯接執行中移除
NULL
這種訪問方式意味着MySQL能在優化階段分解查詢語句,在執行階段甚至用不着再訪問表或者索引。例如從一個索引列裏選取最小值能夠經過單獨查找索引
來完成,不須要在執行訪問表(覆蓋索引)
possible_keys列
這一列顯示了查詢可使用哪些索引,這是基於查詢訪問的列和使用的比較操做符來判斷的。這個列表是在優化過程的早期建立的,所以有些羅列出來的索引可能
對於後續優化過程是沒用的(有些索引不會使用)
key列
這一列顯示了MySQL決定採用哪一個索引來優化對該表的訪問。若是該索引沒有出如今possible_keys列中,那麼MySQL選用它是出於另外的緣由——例如,它可能
選擇了一個覆蓋索引,哪怕沒有where子句。
possible_keys揭示了哪個索引能有助於高效的行查找,而key顯示的是優化採用哪個索引能夠最小化查詢成本
key_len列
該列顯示了MySQL在索引裏使用的字節數(索引列表中定義的字節而不是實際數據佔用的)。若是MySQL正在使用的只是索引裏的某些列,那麼就能夠用這個值
來算出具體是哪些列。MySQL5.5及以前版本只能使用索引的最左前綴(最左列的前綴)。
ref列
這一列顯示了以前的表在key列記錄的索引中查找值所使用的列或常量。
rows列
這列顯示了MySQL估計的爲了找到所需的行而要讀取的行數。這個數字是內嵌循環關聯計劃裏的循環數組。全部的rows列的值相乘,能夠估算出整個查詢會
檢查的行數。
filtered列
5.1新增的,在使用EXPLAIN EXTENDED時出現。顯示的是針對表裏符合某個條件(where子句或聯接條件)的記錄數的百分比所作的一個悲觀估算。將rows列
和這個百分比相乘,就能看到MySQL估算它將和查詢計劃裏前一個表關聯的行數。
Extra列
這一列包含是不適合顯示在其餘列上的額外信息。
Using index
表示MySQL將使用覆蓋索引,以免訪問表。
Using where
意味着MySQL服務器將在存儲引擎行後再進行過濾。許多where條件裏涉及索引中的列,當(而且若是)它讀取索引時,就能被存儲引擎檢驗,所以不是
全部帶where子句的查詢都會顯示Using where,有事Using where的出現就是一個暗示:查詢可受益於不一樣的索引。
Using temporary
這意味着MySQL在對查詢結果排序時會使用一個臨時表
Using filesort
這意味着MySQL會對結果使用給一個外部索引排序,而不是按索引次序從表中讀取行。具體是在內存還
是在磁盤上進行排序無從得知。
Range checked for each record(index map:N)
意味着沒有好用的索引,新的索引將在關聯的每一行上從新估算,N是顯示在possible_keys列中索引
的位圖,而且是冗餘的