mysql優化之explain備忘筆記

WEB發表於2013-07-09

      今天使用explain來檢視sql執行情況的時候發現有的東西忘掉了,故作此篇文章來強化此知識點的記憶。

1.explain作用

exlain 執行結果顯示了mysql 儲存引擎如何使用索引來處理select語句,能夠幫助我們寫出效率更高的sql語句,發揮mysql那些被埋沒的能力。其實update語句也可以使用explainlai檢視其使用情況,需要做的就是將update語句改為select就可以了,後面的條件不變。因為update修改一條記錄時也是要先找到這條記錄的,故可以替換update為select來用explain檢視尋找資料時使用索引的情況。

2.使用方式

在select語句前加上explain就可以了。比如 explain select * from user where uanme="dd";

3.使用例項

 

mysql> explain select log_id,login_time from stat.stat_user_login_log order by login_time;
+----+-------------+---------------------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table               | type  | possible_keys | key        | key_len | ref  | rows | Extra       |
+----+-------------+---------------------+-------+---------------+------------+---------+------+------+-------------+
|  1 | SIMPLE      | stat_user_login_log | index | NULL          | login_time | 4       | NULL |   32 | Using index |
+----+-------------+---------------------+-------+---------------+------------+---------+------+------+-------------+
1 row in set (0.00 sec)

 

4.結果詳解

第一列  id  :select 識別符 select 的查詢序列號

第二列  select_type:select型別 可以為以下任何一種:

  simple:普通的select,不使用多表連結(union) 或子查詢

  primary:最外面的select

  union:union中的第二個或者後面的select

  dependent subquery:子查詢中的第一個select,取決於外面的查詢

  derived:匯出表的select(from子句的子查詢)

第三列 table:輸出的行所引用的表

第四列 type:聯接型別,下面給出各種聯接型別,按照從最佳型別到最壞型別進行排序

  system:表中僅有一行。這是const連線型別的一個特例

  const:表最多隻有一個匹配行,它在查詢開始時被讀取。const表很快,因為它們只讀取一次!const用於用常數值比較PRIMARY KEY或UNIQUE索引的所有部分時。在下面的查詢中,tbl_name可以用於const表:

SELECT * from tbl_name WHERE primary_key=1;
SELECT * from tbl_name WHERE primary_key_part1=1和 primary_key_part2=2

  eq_ref:對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接型別,除了const型別。它用在一個索引的所有部分被聯接使用並且索引是UNIQUEPRIMARY KEY

eq_ref可以用於使用= 操作符比較的帶索引的列。比較值可以為常量或一個使用在該表前面所讀取的表的列的表示式。

在下面的例子中,MySQL可以使用eq_ref聯接來處理ref_tables

  

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;
 
SELECT * FROM ref_table,other_table  WHERE ef_table.key_column_part1=other_table.column
    AND ref_table.key_column_part2=1;

   ref:對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的字首,或如果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量行,該聯接型別是不錯的。

ref可以用於使用=<=>操作符的帶索引的列。

在下面的例子中,MySQL可以使用ref聯接來處理ref_tables

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

 

ref_or_null:該聯接型別如同ref,但是新增了MySQL可以專門搜尋包含NULL值的行。在解決子查詢中經常使用該聯接型別的優化。

在下面的例子中,MySQL可以使用ref_or_null聯接來處理ref_tables

SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;

  index_merge:該聯接型別表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。

      unique_subquery:該型別替換了下面形式的IN子查詢的ref:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

      unique_subquery是一個索引查詢函式,可以完全替換子查詢,效率更高。

      index_subquery:該聯接型別類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

   range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。key_len包含所使用索引的最長關鍵元素。在該型別中ref列為NULL。

當使用=<>>>=<<=IS NULL<=>BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用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:該聯接型別與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引檔案通常比資料檔案小。

當查詢只使用作為單索引一部分的列時,MySQL可以使用該聯接型別。

  ALL:對於每個來自於先前的表的行組合,進行完整的表掃描。如果表是第一個沒標記const的表,這通常不好,並且通常在它情況下差。通常可以增加更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。

第五列 possible_keys:possible_keys列指出MySQL能使用哪個索引在該表中找到行。注意,該列完全獨立於EXPLAIN輸出所示的表的次序。這意味著在possible_keys中的某些鍵實際上不能按生成的表次序使用。

如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查WHERE子句看是否它引用某些列或適合索引的列來提高你的查詢效能。如果是這樣,創造一個適當的索引並且再次用EXPLAIN檢查查詢。

為了看清一張表有什麼索引,使用SHOW INDEX FROM tbl_name

第六列   key:key列顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

 

第七列    key_len:key_len列顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。注意通過key_len值我們可以確定MySQL將實際使用一個多部關鍵字的幾個部分。

第八列    ref:ref列顯示使用哪個列或常數與key一起從表中選擇行。

第九列    rows:rows列顯示MySQL認為它執行查詢時必須檢查的行數。

第十列    Extra:該列包含MySQL解決查詢的詳細資訊。下面解釋了該列可以顯示的不同的文字字串:

       Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜尋更多的行。

       Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。

下面是一個可以這樣優化的查詢型別的例子:

SELECT * 從t1 LEFT JOIN t2 ON t1.id=t2.id
  WHERE t2.id IS NULL;

假定t2.id定義為NOT NULL。在這種情況下,MySQL使用t1.id的值掃描t1並查詢t2中的行。如果MySQLt2中發現一個匹配的行,它知道t2.id絕不會為NULL,並且不再掃描t2內有相同的id值的行。換句話說,對於t1的每個行,MySQL只需要在t2中查詢一次,無論t2內實際有多少匹配的行。

     range checked for each record :MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。對前面的表的每個行組合,MySQL檢查是否可以使用range或index_merge訪問方法來索取行。

這並不很快,但比執行沒有索引的聯接要快得多。

       Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據聯接型別瀏覽所有行併為所有匹配WHERE子句的行儲存排序關鍵字和行的指標來完成排序。然後關鍵字被排序,並按排序順序檢索行。

        Using index:從只使用索引樹中的資訊而不需要進一步搜尋讀取實際的行來檢索表中的列資訊。當查詢只使用作為單一索引一部分的列時,可以使用該策略。

       Using temporary:為了解決查詢,MySQL需要建立一個臨時表來容納結果。典型情況如查詢包含可以按不同情況列出列的GROUP BY和ORDER BY子句時。

      Using where:WHERE子句用於限制哪一個行匹配下一個表或傳送到客戶。除非你專門從表中索取或檢查所有行,如果Extra值不為Using where並且表聯接型別為ALL或index,查詢可能會有一些錯誤。

如果想要使查詢儘可能快,應找出Using filesort Using temporaryExtra值。

        Using sort_union(...)Using union(...)Using intersect(...)

這些函式說明如何為index_merge聯接型別合併索引掃描。

      Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BYDISTINCT查詢的所有列,而不要額外搜尋硬碟訪問實際的表。並且,按最有效的方式使用索引,以便對於每個組,只讀取少量索引條目。

  

 

相關文章