explain的語法爲:explain <table>。
例如:mysql> explain select id,name from user where id=1;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | user | const | PRIMARY | PRIMARY | 8 | const | 1 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
返回的字段分別解釋如下:
id:表示查詢的序號,這條mysql語句裏只有一次查詢,因此序號爲1;
select_type:表示查詢的類型,simple表示簡單查詢。select_type有多種結果可能,下面會做詳細的介紹。
table:這個較好理解,即查詢結果行所在表名稱。注意,如果查詢沒有命中任何表,此處爲NULL。
type:聯接類型。這裏不太容易理解,可以認爲是對查詢語句另一個角度的類型劃分。需要說明的是,這個type只有查詢語句執行後才能判斷結果,而select_type則是從字面語法上對查詢語句的分類。和select_type一樣,會在下面做詳細的介紹。
possible_keys:指mysql可能使用到的索引名稱,而這裏列出的索引並不一定會實際使用到。
key:mysql實際使用的索引,通過key和possible_keys的比較,可以看到那些索引沒有使用到,在此基礎上也就可以進行相應的優化。
key_len:mysql使用的鍵的長度。在這裏要解釋一下,由於複合主鍵的存在,因此,一個索引裏面會有多個列的存在。而key_len可以幫我們確認這個複合主鍵到底使用了哪些列。關於複合鍵,可以參考這篇文章:http://bbs.phpchina.com/blog-52440-186683.html
ref:表示與索引一起做查詢條件的列。這個字段mysql官網並未做充分的說明,網上搜索也未找到資料,如果讀者有了解的歡迎交流。
rows:mysql認定查詢需要檢查的行數。
Extra:一些提示性文本,表示該查詢的詳細信息。Extra字段有助於我們瞭解查詢語句是否使用臨時表、索引、文件排序等。
下面介紹select_type的種類:
simple:上面的例子返回的結果就是simple,只有一個簡單的where。
primary:對於擁有子查詢的sql語句,primary表示當前查詢是最外面的查詢。看下面的這個例子:
圖1
這個sql語句由兩個查詢組成,最外層的對user表的查詢以及裏層對user_info表的查詢。所以外層的查詢select_type爲primary。
union:union查詢中的第二個查詢,這很好理解,例子如下:
圖 2
dependent union:子查詢中的union查詢的第二個查詢,例子如下:
圖3
union result:使用union查詢的結果,如圖2、圖3所示。
subquery:子查詢的第一個select,例子如下:
圖4
dependent subquery:子查詢中的第一個select。與subquery不同的是,dependent subquery表示mysql認爲子查詢與外面的查詢發生了關聯,對於 in子句裏的查詢結果,mysql會將其與外層表進行比較,看是否存在,存在則輸出,不存在則不輸出。可以參考官方文檔的介紹:http://dev.mysql.com/doc/refman/5.5/en/correlated-subqueries.html
derived:導出表的查詢,如圖5所示:
圖5
下面介紹type字段的類型:
system:表示表僅有一行,爲const的特殊情況。
const:表示最多命中一行。
eq_ref:表示一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY。
ref:聯接只使用鍵的最左邊的前綴,或如果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話)。ref和eq_ref舉例如圖6:
圖6
在圖6中,ugc表有主鍵(id,name),而user表有主鍵(id)。因此當聯接爲ugc.id時,爲ref;聯接爲user.id時,爲eq_ref。
ref_or_null:和ref類似,只是添加了對null的搜索。下面這個例子中,to_date字段是一個允許爲null的索引字段。當使用where加or,且or的條件中有一個是is null時出現了 ref_or_null。
圖13(這張圖是後面補上的,所以下標爲13)
index_merge:多個索引使用並集或者交集時,mysql可能會採用索引合併。這並不一定會發生,取決與mysql具體算法,該算法地 址: http://dev.mysql.com/doc/refman/5.1/zh/optimization.html#index-merge-optimization
簡單的例子如下圖
圖7
unique_subquery:子查詢中使用主鍵或unique索引時發生,可參看圖1。
index_subquery:子查詢中使用非唯一索引時發生,這個我也沒找到例子(或者我的mysql並未對這種查詢情況做優化?)。
range:這很好理解,當查詢中出現選擇範圍的條件時,mysql會做range優化,如圖8所示:
圖8
index:掃描單個索引樹,即要查詢的列全部可以從索引中獲取,不需要掃描原樹數據表。如圖9所示:
圖9
all:掃描整個表,效率最低的聯接。例子在上面的一些圖中能找到。
下面介紹Extra字段的種類:
Distinct:一旦找到匹配行,就不繼續搜索了。
not exists:mysql對left join的優化,當left join找到匹配行時,不再查找join表中另外的行。如圖10所示:
圖10
在圖10中,ugc表的name是不允許爲null的,在這裏只要掃描了ugc的一行就知道ugc表中不可能存在"ugc.name is null"的行,因此此處mysql標記爲not exists。
range checked for each record:MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。對前面的表的每個行組合,
MySQL檢 查是否可以使用range或index_merge訪問方法來索取行。如圖11所示:
圖11
在圖11中,photo_id是photo表的一個索引,而ugc.id是一個範圍查詢,且這個範圍裏photo.id是photo表的唯一索引。也就是說,通過第一個查詢條件photo.photo_id得到的行裏含有可以被再次利用的索引photo.id,mysql這時會考慮使用range或者index_merge來獲取數據。
using filesort:官方解釋:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據聯接類型瀏覽所有行併爲所有匹配WHERE子句的行保存排序關鍵字和行的指針來完成排序。然後關鍵字被排序,並按排序順序檢索行。
在我看來,即指需要排序再輸出時,可能需要filesort,一個例子如圖12所示:
圖12
using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。當查詢只使用作爲單一索引一部分的列時,可以使用該策略。例子可參考圖9。
using temporary:爲了解決查詢,MySQL需要創建一個臨時表來容納結果。典型情況如查詢包含可以按不同情況列出列的GROUP BY和ORDER BY子句時。例子可參考圖12。
using where:WHERE子句用於限制哪一個行匹配下一個表或發送到客戶。除非你專門從表中索取或檢查所有行,如果Extra值不爲Using where並且表聯接類型爲ALL或index,查詢可能會有一些錯誤。如果想要使查詢儘可能快,應找出Using filesort 和Using temporary的Extra值。例子圖11。
using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何爲index_merge聯接類型合併索引掃描。例子爲圖7。
using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。並且,按最有效的方式使用索引,以便對於每個組,只讀取少量索引條目。
需要注意的是,相同語句在相同表上的操作得到的explain結果並不一定就前後一致,取決於mysql優化器在分析表的當前物理存儲等因素後作出的執行決定。
參考文章:
mysql官方explain文檔:http://dev.mysql.com/doc/refman/5.1/zh/optimization.html#explain
mysql explain詳解:http://www.cnitblog.com/aliyiyi08/archive/2008/09/09/48878.html
說了這麼多,對於explain還是算一知半解。歡迎看到這篇文章的朋友與我交流。