1. 程式人生 > >mysql中explain的用法和解釋

mysql中explain的用法和解釋

對於mysql查詢效能分析時經常使用explain關鍵字對查詢語句進行分析,就explain相關欄位進行記錄。

explain的每個輸出行提供一個表達額相關資訊,每個行包括下面的列

  1. id
  2. select_type
  3. table
  4. type
  5. possible_keys
  6. key
  7. key_len
  8. ref
  9. rows
  10. 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時可能表示有問題。