mysql中explain的用法和解釋
對於mysql查詢效能分析時經常使用explain關鍵字對查詢語句進行分析,就explain相關欄位進行記錄。
explain的每個輸出行提供一個表達額相關資訊,每個行包括下面的列
- id
- select_type
- table
- type
- possible_keys
- key
- key_len
- ref
- rows
- extra
(這裡僅僅是為了顯示各個欄位)
下面就各欄位含義進行介紹
id
本次查詢的識別符號,在查詢中的每個select都有一個順序的數值
select_type
select 的型別,可能有以下幾種:
- simple 簡單的select,沒有使用union或子查詢
- primary 最層的select
- union 第二層,在select後使用了union
- dependent union 子查詢的第一個select,依賴於外部子查詢
- subquery 子查詢的第一個select
- dependent subquery 子查詢的第一個subquery,依賴於外部的子查詢
- derived 派生表select(from 子句中的子查詢)
table
記錄查詢引用的表
type
表連線型別,以下是各種不同連線型別(從好到壞)
一般來說,得保證查詢至少達到range級別,最好能達到ref。
- system:表只有一行資料(相當於系統表),這是const表連線型別的一個特例
const:表中最多隻有一行匹配記錄,在查詢一開始就會被讀取出來。由於只有一行記錄,在餘下的優化程式裡該行記錄的欄位值可以被當作是一個恆定值。const表查詢起來非常快,因為只要讀取一次!const 用於在和 primary key 或unique 索引中有固定值比較的情形。
eq_ref:對於每個來自於前面的表的行組合,從該表中讀取一行。除了const型別,這是最好的連線型別。它用在索引所有部分都用於做連線並且這個索引是一個primary key 或 unique 型別。eq_ref可以用於在進行”=”做比較時檢索欄位。比較的值可以是固定值或者是表示式,表達示中可以使用表裡的欄位,它們在讀表之前已經準備好了。
ref:對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的字首,或如果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量行,該聯接型別是不錯的。 ref還可以用於檢索欄位使用 =操作符來比較的時候。
ref_or_null:這種連線型別類似 ref,不同的是mysql會在檢索的時候額外的搜尋包含null 值的記錄。這種連線型別的優化是從mysql4.1.1開始的,它經常用於子查詢。
index_merge 該聯接型別表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
unique_subquery:這種型別用例如一下形式的 in 子查詢來替換 ref:
value in (select primary_key from single_table where some_expr),只是用來完全替換子查詢的索引查詢函式效率更高了。- index_subquery:這種連線型別類似 unique_subquery。它用子查詢來代替in,不過它用於在子查詢中沒有唯一索引的情況下。
-range:在給定範圍的記錄中,利用索引來取得一條資料。key欄位表示使用了哪個索引。key_len欄位包括了使用的鍵的最長部分。這種型別時 ref 欄位值是 null。range用於將某個欄位和一個定植用以下任何操作符比較時 =, <>, >,>=, <, <=, is null, <=>, between, 或 in:
select * from tbl_name where key_column = 10; select * fromtbl_name where key_column between 10 and 20; select * from tbl_namewhere key_column in (10,20,30); select * from tbl_name wherekey_part1= 10 and key_part2 in (10,20,30);
index:連線型別跟 all 一樣,不同的是它只掃描索引樹。它通常會比 all快點,因為索引檔案通常比資料檔案小。mysql在查詢的欄位知識單獨的索引的一部分的情況下使用這種連線型別。
all:將對該表做全部掃描以和從前一個表中取得的記錄作聯合。這時候如果第一個表沒有被標識為const的話就不大好了,在其他情況下通常是非常糟糕的。正常地,可以通過增加索引使得能從表中更快的取得記錄以避免all。
possible_keys
possible_keys欄位是指 mysql在搜尋表記錄時可能使用哪個索引。注意,這個欄位完全獨立於explain 顯示的表順序。這就意味著 possible_keys裡面所包含的索引可能在實際的使用中沒用到。如果這個欄位的值是null,就表示沒有索引被用到。這種情況下,就可以檢查 where子句中哪些欄位那些欄位適合增加索引以提高查詢的效能。就這樣,建立一下索引,然後再用explain 檢查一下。
key
key欄位顯示了mysql實際上要用的索引。當沒有任何索引被用到的時候,這個欄位的值就是null。想要讓mysql強行使用或者忽略在 possible_keys欄位中的索引列表,可以在查詢語句中使用關鍵字force index, use index,或 ignore index。如果是 myisam 和 bdb 型別表,可以使用 analyzetable 來幫助分析使用使用哪個索引更好。如果是 myisam型別表,執行命令 myisamchk –analyze也是一樣的效果。
key_len
key_len 欄位顯示了mysql使用索引的長度。當 key 欄位的值為 null時,索引的長度就是 null。注意,key_len的值可以告訴你在聯合索引中mysql會真正使用了哪些索引。
ref
ref 欄位顯示了哪些欄位或者常量被用來和 key配合從表中查詢記錄出來。
rows
rows 欄位顯示了mysql認為在查詢中應該檢索的記錄數。
extra
- distinct
mysql當找到當前記錄的匹配聯合結果的第一條記錄之後,就不再搜尋其他記錄了。 - not exists
mysql在查詢時做一個 left join優化時,當它在當前表中找到了和前一條記錄符合 left join條件後,就不再搜尋更多的記錄了。下面是一個這種型別的查詢例子:
select * from t1 left join t2 on t1.id=t2.id where t2.id isnull;
假使 t2.id 定義為 not null。這種情況下,mysql將會掃描表 t1並且用 t1.id 的值在 t2 中查詢記錄。當在 t2中找到一條匹配的記錄時,這就意味著 t2.id 肯定不會都是null,就不會再在 t2 中查詢相同 id值的其他記錄了。也可以這麼說,對於 t1 中的每個記錄,mysql只需要在t2 中做一次查詢,而不管在 t2 中實際有多少匹配的記錄。 - range checked for each record
mysql沒找到合適的可用的索引。取代的辦法是,對於前一個表的每一個行連線,它會做一個檢驗以決定該使用哪個索引(如果有的話),並且使用這個索引來從表裡取得記錄。這個過程不會很快,但總比沒有任何索引時做表連線來得快。 - using filesort:
mysql需要額外的做一遍從而以排好的順序取得記錄。排序程式根據連線的型別遍歷所有的記錄,並且將所有符合 where條件的記錄的要排序的鍵和指向記錄的指標儲存起來。這些鍵已經排完序了,對應的記錄也會按照排好的順序取出來。 - using index
欄位的資訊直接從索引樹中的資訊取得,而不再去掃描實際的記錄。這種策略用於查詢時的欄位是一個獨立索引的一部分。 - using temporary
mysql需要建立臨時表儲存結果以完成查詢。這種情況通常發生在查詢時包含了groupby 和 order by 子句,它以不同的方式列出了各個欄位。 - using where
where子句將用來限制哪些記錄匹配了下一個表或者傳送給客戶端。除非你特別地想要取得或者檢查表種的所有記錄,否則的話當查詢的extra 欄位值不是 using where 並且表連線型別是 all 或 index時可能表示有問題。