MySQL語句explain詳解

我們一般再檢查一個SQL語句執行效率的時候,通常會首先用explain來看下該語句的相關情況。雖然經常使用,但時候你深刻的理解了其結果中每個字段的含義呢?其中type字段是我們關注的重中之重。type字段的歸納:

    連接類型
    system          表只有一行
    const           表最多隻有一行匹配,通用用於主鍵或者唯一索引比較時
    eq_ref          每次與之前的表合併行都只在該表讀取一行,這是除了system,const之外最好的一種,
                    特點是使用=,而且索引的所有部分都參與join且索引是主鍵或非空唯一鍵的索引
    ref             如果每次只匹配少數行,那就是比較好的一種,使用=或<=>,可以是左覆蓋索引或非主鍵或非唯一鍵
    fulltext        全文搜索
    ref_or_null     與ref類似,但包括NULL
    index_merge     表示出現了索引合併優化(包括交集,並集以及交集之間的並集),但不包括跨表和全文索引。
                    這個比較複雜,目前的理解是合併單表的範圍索引掃描(如果成本估算比普通的range要更優的話)
    unique_subquery 在in子查詢中,就是value in (select...)把形如“select unique_key_column”的子查詢替換。
                    PS:所以不一定in子句中使用子查詢就是低效的!
    index_subquery  同上,但把形如”select non_unique_key_column“的子查詢替換
    range           常數值的範圍
    index           a.當查詢是索引覆蓋的,即所有數據均可從索引樹獲取的時候(Extra中有Using Index);
                    b.以索引順序從索引中查找數據行的全表掃描(無 Using Index);
                    c.如果Extra中Using Index與Using Where同時出現的話,則是利用索引查找鍵值的意思;
                    d.如單獨出現,則是用讀索引來代替讀行,但不用於查找
    all             全表掃描</code>

下面是explain所有輸出結果的詳解:

一.語法

explain < table_name >

例如: explain select * from t1 where id=888;

二.explain輸出解釋

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

| id | select_type | table | type  | possible_keys     | key     | key_len | ref   | rows | Extra |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

1.id

  我的理解是SQL執行的順利的標識,SQL從大到小的執行.


例如:

mysql> explain select * from (select * from ( select * from t1 where id=888) a) b;

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  2 | DERIVED     | <derived3> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  3 | DERIVED     | t1         | const  | PRIMARY,idx_id    | PRIMARY | 4       |      |    1 |       |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+


很顯然這條SQL是從裏向外的執行,就是從id=3 向上執行.


2. select_type


就是select類型,可以有以下幾種


(1) SIMPLE

簡單SELECT(不使用UNION或子查詢等) 例如:

mysql> explain select * from t1 where id=888;

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

| id | select_type | table | type  | possible_keys     | key     | key_len | ref   | rows | Extra |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

|  1 | SIMPLE      | t1    | const | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 |       |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+


(2). PRIMARY


我的理解是最外層的select.例如:


mysql> explain select * from (select * from t1 where id=888) a ;

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  2 | DERIVED     | t1         | const  | PRIMARY,idx_id    | PRIMARY | 4       |      |    1 |       |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+


(3).UNION


UNION中的第二個或後面的SELECT語句.例如

mysql> explain select * from t1 where id=888 union all select * from t1 ;

+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+

| id | select_type  | table      | type  | possible_keys     | key     | key_len | ref   | rows | Extra |

+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+

|  1 | PRIMARY      | t1         | const | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 |       |

|  2 | UNION        | t1         | ALL   | NULL              | NULL    | NULL    | NULL  | 1000 |       |

|NULL | UNION RESULT | <union1,2> | ALL   | NULL              | NULL    | NULL    | NULL  | NULL |       |

+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+


(4).DEPENDENT UNION


UNION中的第二個或後面的SELECT語句,取決於外面的查詢


mysql> explain select * from t1 where id in (select id from t1 where id=888 union all select id from t1)  ;

+----+--------------------+------------+--------+-------------------+---------+---------+-------+------+--------------------------+

| id | select_type        | table      | type   | possible_keys     | key     | key_len | ref   | rows | Extra                    |

+----+--------------------+------------+--------+-------------------+---------+---------+-------+------+--------------------------+

|  1 | PRIMARY            | t1         | ALL    | NULL              | NULL    | NULL    | NULL  | 1000 | Using where              |

|  2 | DEPENDENT SUBQUERY | t1         | const  | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 | Using index              |

|  3 | DEPENDENT UNION    | t1         | eq_ref | PRIMARY,idx_id    | PRIMARY | 4       | func  |    1 | Using where; Using index |

|NULL | UNION RESULT       | <union2,3> | ALL    | NULL              | NULL    | NULL    | NULL  | NULL |                          |

+----+--------------------+------------+--------+-------------------+---------+---------+-------+------+--------------------------+


(4).UNION RESULT


UNION的結果。


mysql> explain select * from t1 where id=888 union all select * from t1 ;

+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+

| id | select_type  | table      | type  | possible_keys     | key     | key_len | ref   | rows | Extra |

+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+

|  1 | PRIMARY      | t1         | const | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 |       |

|  2 | UNION        | t1         | ALL   | NULL              | NULL    | NULL    | NULL  | 1000 |       |

|NULL | UNION RESULT | <union1,2> | ALL   | NULL              | NULL    | NULL    | NULL  | NULL |       |

+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+


(5).SUBQUERY


子查詢中的第一個SELECT.


mysql> explain select * from t1 where id = (select id from t1 where id=888 )  ;

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------------+

| id | select_type | table | type  | possible_keys     | key     | key_len | ref   | rows | Extra       |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------------+

|  1 | PRIMARY     | t1    | const | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 |             |

|  2 | SUBQUERY    | t1    | const | PRIMARY,idx_id    | PRIMARY | 4       |       |    1 | Using index |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------------+


(6).  DEPENDENT SUBQUERY


子查詢中的第一個SELECT,取決於外面的查詢


mysql> explain select id from t1 where id in (select id from t1 where id=888 )  ;

+----+--------------------+-------+-------+-------------------+---------+---------+-------+------+--------------------------+

| id | select_type        | table | type  | possible_keys     | key     | key_len | ref   | rows | Extra                    |

+----+--------------------+-------+-------+-------------------+---------+---------+-------+------+--------------------------+

|  1 | PRIMARY            | t1    | index | NULL              | PRIMARY | 4       | NULL  | 1000 | Using where; Using index |

|  2 | DEPENDENT SUBQUERY | t1    | const | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 | Using index              |

+----+--------------------+-------+-------+-------------------+---------+---------+-------+------+--------------------------+



(7).DERIVED


派生表的SELECT(FROM子句的子查詢)


mysql> explain select * from (select * from t1 where id=888) a ;

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  2 | DERIVED     | t1         | const  | PRIMARY,idx_id    | PRIMARY | 4       |      |    1 |       |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+



3.table


顯示這一行的數據是關於哪張表的.

有時不是真實的表名字,看到的是derivedx(x是個數字,我的理解是第幾步執行的結果)


mysql> explain select * from (select * from ( select * from t1 where id=888) a) b;

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  2 | DERIVED     | <derived3> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  3 | DERIVED     | t1         | const  | PRIMARY,idx_id    | PRIMARY | 4       |      |    1 |       |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+


4.type


這列很重要,顯示了連接使用了哪種類別,有無使用索引.

從最好到最差的連接類型爲const、eq_reg、ref、range、indexhe和ALL 


(1).system


這是const聯接類型的一個特例。表僅有一行滿足條件.如下(t1表上的id是 primary key)


mysql> explain select * from (select * from t1 where id=888) a ;

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |

|  2 | DERIVED     | t1         | const  | PRIMARY,idx_id    | PRIMARY | 4       |      |    1 |       |

+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+


(2).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;


例如:

mysql> explain select * from t1 where id=888;

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

| id | select_type | table | type  | possible_keys     | key     | key_len | ref   | rows | Extra |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+

|  1 | SIMPLE      | t1    | const | PRIMARY,idx_id    | PRIMARY | 4       | const |    1 |       |

+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+



(3). eq_ref


對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY 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 ref_table.key_column_part1=other_table.column

    AND ref_table.key_column_part2=1;


例如

mysql> create unique index  idx_id    on t1(id) ;

Query OK, 1000 rows affected (0.03 sec)

Records: 1000  Duplicates: 0  Warnings: 0


mysql> explain select * from t1,t4 where t1.id=t4.accountid;

+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+

| id | select_type | table | type   | possible_keys     | key       | key_len | ref                  | rows | Extra |

+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+

|  1 | SIMPLE      | t4    | ALL    | NULL              | NULL      | NULL    | NULL                 | 1000 |       |

|  1 | SIMPLE      | t1    | eq_ref | PRIMARY,idx_id    | idx_id    | 4       | dbatest.t4.accountid |    1 |       |

+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+


(4).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;


例如:


mysql> drop index idx_id    on t1;

Query OK, 1000 rows affected (0.03 sec)

Records: 1000  Duplicates: 0  Warnings: 0


mysql> create index idx_id    on t1(id) ;

Query OK, 1000 rows affected (0.04 sec)

Records: 1000  Duplicates: 0  Warnings: 0


mysql> explain select * from t1,t4 where t1.id=t4.accountid;

+----+-------------+-------+------+-------------------+-----------+---------+----------------------+------+-------+

| id | select_type | table | type | possible_keys     | key       | key_len | ref                  | rows | Extra |

+----+-------------+-------+------+-------------------+-----------+---------+----------------------+------+-------+

|  1 | SIMPLE      | t4    | ALL  | NULL              | NULL      | NULL    | NULL                 | 1000 |       |

|  1 | SIMPLE      | t1    | ref  | PRIMARY,idx_id    | idx_id    | 4       | dbatest.t4.accountid |    1 |       |

+----+-------------+-------+------+-------------------+-----------+---------+----------------------+------+-------+

2 rows in set (0.00 sec)


(5).  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;


(6). index_merge


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


例如:

mysql> explain select * from t4 where id=888 or accountid=31754306 ;

+----+-------------+-------+-------------+----------------------------+----------------------------+---------+------+------+------------------------------------------------------+

| id | select_type | table | type        | possible_keys              | key                        | key_len | ref  | rows | Extra                                                |

+----+-------------+-------+-------------+----------------------------+----------------------------+---------+------+------+------------------------------------------------------+

|  1 | SIMPLE      | t4    | index_merge | idx_t4_id,idx_t4_accountid | idx_t4_id,idx_t4_accountid | 4,4     | NULL |    2 | Using union(idx_t4_id,idx_t4_accountid); Using where |

+----+-------------+-------+-------------+----------------------------+----------------------------+---------+------+------+------------------------------------------------------+

1 row in set (0.00 sec)


(7). unique_subquery


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


value IN (SELECT primary_key FROM single_table WHERE some_expr)

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


(8).index_subquery


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


value IN (SELECT key_column FROM single_table WHERE some_expr)


(9).range


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


當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用range


mysql> explain select * from t1 where id=888 or id=3952603 ;

+----+-------------+-------+-------+-------------------+-----------+---------+------+------+-------------+

| id | select_type | table | type  | possible_keys     | key       | key_len | ref  | rows | Extra       |

+----+-------------+-------+-------+-------------------+-----------+---------+------+------+-------------+

|  1 | SIMPLE      | t1    | range | PRIMARY,idx_id    | idx_id    | 4       | NULL |    2 | Using where |

+----+-------------+-------+-------+-------------------+-----------+---------+------+------+-------------+

1 row in set (0.02 sec)


(10).index


該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因爲索引文件通常比數據文件小。


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


(11). ALL


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



5.possible_keys


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


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


6. key


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


7.key_len


key_len列顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度爲NULL。

使用的索引的長度。在不損失精確性的情況下,長度越短越好 


8. ref


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


9. rows


rows列顯示MySQL認爲它執行查詢時必須檢查的行數。


10. Extra


該列包含MySQL解決查詢的詳細信息,下面詳細.


(1).Distinct 

一旦MYSQL找到了與行相聯合匹配的行,就不再搜索了 


(2).Not exists 

MYSQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行, 


就不再搜索了 


(3).Range checked for each 


Record(index map:#) 

沒有找到理想的索引,因此對於從前面表中來的每一個行組合,MYSQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一 


(4).Using filesort 

看到這個的時候,查詢就需要優化了。MYSQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行 


(5).Using index 

列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的全部的請求列都是同一個索引的部分的時候 


(6).Using temporary 

看到這個的時候,查詢需要優化了。這裏,MYSQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上 


(7).Using where

使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章