EXPLAIN語句提供有關MySQL如何執行語句的信息。EXPLAIN與SELECT,DELETE,INSERT,REPLACE和UPDATE語句一塊兒使用。優化
EXPLAIN爲SELECT語句中使用的每一個表返回一行信息。它按照MySQL在處理語句時讀取它們的順序列出了輸出中的表。 MySQL使用嵌套循環鏈接方法解析全部鏈接。這意味着MySQL從第一個表中讀取一行,而後在第二個表,第三個表中找到匹配的行,依此類推。處理完全部表後,MySQL輸出所選列,並經過表列表回溯,直到找到一個表,其中有更多匹配的行。從這個表中讀取下一行,而後繼續處理下一個表。spa
1. EXPLAIN 輸出列3d
說下幾個關鍵的列:指針
2. 鏈接類型code
鏈接類型,順序從最好到最差,依次是: orm
systemblog
表只有一行。這是const join類型的特例。排序
const索引
表最多有一個匹配行,在查詢開始時讀取。由於只有一行,因此這一行中的列的值能夠被優化器的其他部分視爲常量。const表很是快,由於它們只被讀取一次。it
當你用PRIMARY KEY或UNIQUE索引的全部部分與常量值進行比較時,將使用const。
例如,下面的表tbl_name能夠被當作const表:
SELECT * FROM tbl_name WHERE primary_key=1; SELECT * FROM tbl_name WHERE primary_key_part1=1 AND primary_key_part2=2;
eq_ref
對於前表中的每一行組合,從這個表中讀取一行。除了system和const類型,這是可能的最好的聯接類型。當一個索引的全部部分都被聯接使用而且索引是PRIMARY KEY或UNIQUE NOT NULL索引時,使用它。
eq_ref能夠用於使用=操做符進行比較的索引列。比較值能夠是一個常量,也能夠是使用在此表以前讀取的表中的列的表達式。
例如,下面的例子中MySQL可使用eq_ref鏈接來處理ref_table:
SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
ref
對於前表中的行的每種組合,將從該表中讀取具備匹配索引值的全部行。若是聯接僅使用key的最左前綴,或者若是key不是PRIMARY KEY或UNIQUE索引(換句話說,若是聯接沒法基於key值選擇單個行),則使用ref。若是使用的key僅匹配幾行,則這是一種很好的聯接類型。
ref可用於使用=或<=>運算符進行比較的索引列。
例如,下面的例子中,MySQL能夠用ref鏈接來處理ref_table:
SELECT * FROM ref_table WHERE key_column=expr; SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
fulltext
使用FULLTEXT索引執行鏈接
ref_or_null
這種鏈接類型相似於ref,可是MySQL會額外搜索包含NULL值的行。此聯接類型優化最經常使用於解析子查詢。
例如,下面的例子中,MYSQL可使用ref_or_null來處理ref_table:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
index_merge
這種鏈接類型代表使用了索引合併優化。在這種狀況下,輸出行中的key列包含使用的索引列表,而key_len包含所使用索引的最長key部分列表。
unique_subquery
此類型將eq_ref替換爲如下形式的某些IN子查詢:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery
與unique_subquery相似,它代替了IN子查詢,但適用於如下形式的子查詢中的非惟一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
range
只檢索給定範圍內的行,並使用索引來選擇行。輸出行中的key列指示使用了哪一個索引。key_len包含所使用的最長的key部分。對於這種類型,ref列爲NULL。
使用=,<>,>,> =,<,<=,IS NULL,<=>,BETWEEN,LIKE或IN()運算符將key列與常量進行比較時,可使用range:
SELECT * FROM tbl_name WHERE key_column = 10; SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20; SELECT * FROM tbl_name WHERE key_column IN (10,20,30); SELECT * FROM tbl_name WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
index
index鏈接類型與all是同樣的,區別在於index鏈接類型掃描的時候索引樹。一般,只發生在如下兩種狀況:
ALL
對前表的行的每一個組合進行全表掃描。若是該表是未標記爲const的第一個表,則一般很差,而且在全部其餘狀況下一般很是糟糕。一般,能夠經過添加索引來避免ALL,這些索引容許基於早期表中的常量值或列值從表中檢索行。
3. Extra列
關於Extra列的輸出,只說幾個常見的:
Using filesort
MySQL必須作一次額外操做,以找出如何按排序順序檢索行。排序是經過根據聯接類型遍歷全部行並存儲與WHERE子句匹配的全部行的排序key和指向該行的指針來完成的。而後對key進行排序,並按排序順序檢索行。
Using index
僅使用索引樹中的信息從表中檢索列信息,而不須要執行額外的查找來讀取實際行。當查詢只使用屬於單個索引的列時,可使用此策略。
Using temporary
爲了解析查詢,MySQL須要建立一個臨時表來保存結果。一般,若是查詢包含以不一樣方式展現列的GROUP BY和ORDER BY子句,則會發生這種狀況。
Using where
WHERE子句用於限制哪些行匹配下一個表或發送給客戶端。除非你打算從表中獲取或檢查全部行,不然若是額外的值沒有使用where,而且錶鏈接類型是all或index,則查詢中可能出現錯誤。
4. 優化ORDER BY
在某些狀況下,MySQL可能會使用一個索引來知足ORDER BY子句,從而避免執行filesort操做所涉及的額外排序。
假設在(key_part1, key_part2)上有一個索引,下面的查詢可使用索引來解析ORDER BY部分。優化器是否真的這樣作,取決於若是還必須讀取索引以外的時,讀取索引是否比表掃描更有效。
SELECT * FROM t1 ORDER BY key_part1, key_part2;
上面的語句,查詢使用SELECT *,這可能會選擇比key_part1和key_part2更多的列。在這種狀況下,掃描整個索引並查找錶行以查找索引中未包含的列可能比掃描表並排序結果要昂貴。若是是這樣,則優化器不太可能使用索引。若是SELECT *僅選擇索引列,則使用索引並避免排序。
下面這個查詢中,key_part1是常量,所以經過索引訪問的全部行都按key_part2順序排列,而且若是WHERE子句的選擇性足以使索引範圍掃描比表掃描便宜,則在(key_part1,key_part2)上的索引能夠避免排序:
SELECT * FROM t1 WHERE key_part1 = constant ORDER BY key_part2;