理解MySQL中的explain

前言

我們可以使用explain命令來查看MySQL查詢優(yōu)化器的執(zhí)行計劃是怎么來優(yōu)化查詢的。通過結(jié)果反饋,我們能更好地選擇索引,同時也能寫出更好的查詢語句。

【注】:本節(jié)我們使用的MySQL版本為5.7.11。

語法

explain命令可作用于具體的表。也可作用于DML語句,包括SELECT、DELETEINSERT、REPLACEUPDATE

當(dāng)作用于具體表時,和desc命令效果相同,用于描述表的信息,結(jié)果信息包括:字段名稱、字段類型、是否為null、是否主鍵、默認(rèn)值等等。

-- explain作用于表
explain `{tableName}`;

當(dāng)作用于DML語句時,可用于查看執(zhí)行計劃。

  1. 因為REPLACEINSERT語句相對來說較為簡單,本節(jié)不會額外分析他們。
  2. DELETE、UPDATESELECT有相似之處,都可以寫WHERE條件,所以本節(jié)僅以SELECT為例來進行分析。
-- explain作用于DML
explain DML語句;

列信息詳解

我們先給出最簡單的例子,然后對例子中的每一列進行詳細(xì)分析。所有的分析都借鑒了官方說明。

最簡單的例子

我們創(chuàng)建一個user表,其DDL如下。

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `username` varchar(20) NOT NULL COMMENT '用戶名',
  `password` varchar(20) NOT NULL COMMENT '密碼',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

執(zhí)行explain之后,我們得到如下結(jié)果。

mysql> explain select * from user where id = 1;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | user  | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

1. id

id列可以是一個正整數(shù)或null,且滿足下面的規(guī)則。

  1. id大的先執(zhí)行
  2. id相同的,按照順序從上往下執(zhí)行
  3. id為null表示是一個結(jié)果集,不是一個查詢

2. select_type

用于表示查詢中每個SELECT子句的類型,可能出現(xiàn)的枚舉值如下

1. SIMPLE
2. PRIMARY
3. UNION
4. DEPENDENT UNION
5. UNION RESULT
6. SUBQUERY
7. DEPENDENT SUBQUERY
8. DERIVED
9. UNCACHEABLE SUBQUERY
10. UNCACHEABLE UNION

2.1.SIMPLE

簡單查詢,子查詢和UNION查詢之外的其他查詢。

mysql> explain select * from user where id = 1;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | user  | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

2.2. PRIMARY

含有子查詢或者UNION查詢時,最外層或者最遠(yuǎn)的查詢。

mysql> explain select username from user a where id = 1 union select username from user b  where id = 3;
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
| id | select_type  | table      | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra           |
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
|  1 | PRIMARY      | a          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
|  2 | UNION        | b          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)

2.3. UNION

UNION語句中的第二個或更后面的查詢子句,第一個為PRIMARY。

mysql> explain select username from user a where id = 1 union select username from user b  where id = 3;
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
| id | select_type  | table      | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra           |
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
|  1 | PRIMARY      | a          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
|  2 | UNION        | b          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)

2.4. DEPENDENT UNION

和UNION類似,只是表示外部查詢需要對其進行依賴。比如下面的查詢,會先查詢id列值為2和3的記錄,然后納入select * from user的查詢條件中。

mysql> explain select * from user where username in (select username from user a where id = 1 union select username from user b  where id = 3);
+----+--------------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
| id | select_type        | table      | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra           |
+----+--------------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
|  1 | PRIMARY            | user       | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  |    3 |   100.00 | Using where     |
|  2 | DEPENDENT SUBQUERY | a          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
|  3 | DEPENDENT UNION    | b          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
| NULL | UNION RESULT       | <union2,3> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  | NULL |     NULL | Using temporary |
+----+--------------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
4 rows in set, 1 warning (0.00 sec)

2.5. UNION RESULT

用于表示UNION的結(jié)果,因為不需要參與查詢,所以id列為null。

mysql> explain select * from user where username in (select username from user a where id = 1 union select username from user b  where id = 3);
+----+--------------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
| id | select_type        | table      | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra           |
+----+--------------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
|  1 | PRIMARY            | user       | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  |    3 |   100.00 | Using where     |
|  2 | DEPENDENT SUBQUERY | a          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
|  3 | DEPENDENT UNION    | b          | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL            |
| NULL | UNION RESULT       | <union2,3> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  | NULL |     NULL | Using temporary |
+----+--------------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-----------------+
4 rows in set, 1 warning (0.00 sec)

2.6. SUBQUERY

子查詢里面的第一個SELECT子句。

mysql> explain select password from user a where id = (select id from user b  where id = 3);
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | PRIMARY     | a     | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL        |
|  2 | SUBQUERY    | b     | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

2.7. DEPENDENT SUBQUERY

子查詢內(nèi)部的第一個查詢子句,同時外層查詢依賴子查詢。

mysql> explain select update_time from user_extra as ue where exists (select id from user where user.id = ue.user_id and id = 1);
+----+--------------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type        | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+--------------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | PRIMARY            | ue    | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  |    1 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | user  | NULL       | const | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | Using index |
+----+--------------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec)

2.8. DERIVED

表示派生關(guān)系,在FROM子句里面有子查詢,且子查詢帶分組時,會出現(xiàn)此種情況。

mysql> explain SELECT id FROM (SELECT id FROM user GROUP BY id) AS tmp;
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL |    3 |   100.00 | NULL        |
|  2 | DERIVED     | user       | NULL       | index | PRIMARY       | PRIMARY | 8       | NULL |    3 |   100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

2.9. UNCACHEABLE SUBQUERY和UNCACHEABLE UNION

主要出現(xiàn)在子查詢有隨機函數(shù)和UNION有隨機函數(shù)的場景

3. table

該列表示被查詢的表名,可能出現(xiàn)下面的值

  1. <unionM,N> // select_type為union,且union關(guān)聯(lián)的id為M和N
  2. <derivedN> // select_type為derived,且是從id為N的結(jié)果導(dǎo)出的
  3. <subqueryN> // select_type為subquery,且是id為N的子查詢

4. type

該列表示MySQL查詢到具體數(shù)據(jù)行的方式,通常我們將其叫做訪問類型,其值從優(yōu)到差分別如下:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

  1. system & const

當(dāng)用到主鍵索引或唯一索引時其值為const。system是const的特例,當(dāng)查詢系統(tǒng)表,且系統(tǒng)表里面只有一行數(shù)據(jù)時出現(xiàn)。

explain select * from user;
  1. eq_ref

主鍵索引或唯一索引作為兩個表的連接方式時,通常和=一起使用。

explain select * from user, user_extra where user.id = user_extra.user_id;
  1. ref

用到了索引,但不是主鍵索引和唯一索引。

explain select * from user where uuid = 'x';
  1. ref_or_null

類似于ref,但是可以查詢包含null的行,通常用在子查詢里面。

  1. index_merge

當(dāng)使用多個條件進行交集或并集時出現(xiàn)。


  1. range

對索引列進行范圍查找時出現(xiàn),比如between、in>、<

explain select * from user where id > 1;
  1. index

全表掃描,但是只查詢索引列的值,因此只需要掃描索引樹即可。

explain select id from user;
  1. ALL

全表掃描,在服務(wù)端進行邏輯處理。性能最差的一種方式。

explain select * from user;

5. possible_keys

指出MySQL可能用到的索引字段,它會按照順序,把所有可能涉及到的索引都列出來,但并不是每個索引都會用到。

6. keys

指出MySQL實際用到的索引字段。

7. key_len

表示使用的索引最大長度。在組合索引的情況下,該字段使用,羅列出每個索引字段的長度。需要注意的是,key_len只是表結(jié)構(gòu)定義的翻譯。在同樣的條件下,key_len越短,查詢的效率越高。

8. ref

ref顯示哪些列或者常量被用于和索引列key進行對比。如果值為func,則表示此值是通過函數(shù)計算得出。

9. rows

Mysql認(rèn)為需要查詢的行數(shù)。

10. filtered

該列給出了一個百分比的值,這個百分比值和rows列的值一起使用,可以估計出那些將要和QEP中的前一個表進行連接的行的數(shù)目。前一個表就是指id列的值比當(dāng)前表的id小的表。

11. extra

該列包含對于MySQL查詢的附加描述信息,當(dāng)該列出現(xiàn)Using filesort或者Using temporary時,我們必須對我們的查詢語句進行優(yōu)化。

參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Mysql概述 數(shù)據(jù)庫是一個易于訪問和修改的信息集合。它允許使用事務(wù)來確保數(shù)據(jù)的安全性和一致性,并能快速處理百萬條...
    彥幀閱讀 13,962評論 10 460
  • 轉(zhuǎn)自:http://blog.chinaunix.net/uid-540802-id-3419311.html e...
    小陳阿飛閱讀 1,217評論 0 2
  • explain關(guān)鍵字可以模擬優(yōu)化器執(zhí)行SQL語句,從而知道MySQL是 如何處理你的SQL語句的。分析你的查詢語句...
    Chting閱讀 1,619評論 0 2
  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 10,123評論 0 44
  • MYSQL 基礎(chǔ)知識 1 MySQL數(shù)據(jù)庫概要 2 簡單MySQL環(huán)境 3 數(shù)據(jù)的存儲和獲取 4 MySQL基本操...
    Kingtester閱讀 8,060評論 5 115

友情鏈接更多精彩內(nèi)容