前言
我們可以使用explain命令來查看MySQL查詢優(yōu)化器的執(zhí)行計劃是怎么來優(yōu)化查詢的。通過結(jié)果反饋,我們能更好地選擇索引,同時也能寫出更好的查詢語句。
【注】:本節(jié)我們使用的MySQL版本為5.7.11。
語法
explain命令可作用于具體的表。也可作用于DML語句,包括SELECT、DELETE、INSERT、REPLACE和UPDATE。
當(dāng)作用于具體表時,和desc命令效果相同,用于描述表的信息,結(jié)果信息包括:字段名稱、字段類型、是否為null、是否主鍵、默認(rèn)值等等。
-- explain作用于表
explain `{tableName}`;
當(dāng)作用于DML語句時,可用于查看執(zhí)行計劃。
- 因為
REPLACE和INSERT語句相對來說較為簡單,本節(jié)不會額外分析他們。 -
DELETE、UPDATE和SELECT有相似之處,都可以寫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ī)則。
- id大的先執(zhí)行
- id相同的,按照順序從上往下執(zhí)行
- 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)下面的值
- <unionM,N> // select_type為union,且union關(guān)聯(lián)的id為M和N
- <derivedN> // select_type為derived,且是從id為N的結(jié)果導(dǎo)出的
- <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
- system & const
當(dāng)用到主鍵索引或唯一索引時其值為const。system是const的特例,當(dāng)查詢系統(tǒng)表,且系統(tǒng)表里面只有一行數(shù)據(jù)時出現(xiàn)。
explain select * from user;
- eq_ref
主鍵索引或唯一索引作為兩個表的連接方式時,通常和=一起使用。
explain select * from user, user_extra where user.id = user_extra.user_id;
- ref
用到了索引,但不是主鍵索引和唯一索引。
explain select * from user where uuid = 'x';
- ref_or_null
類似于ref,但是可以查詢包含null的行,通常用在子查詢里面。
- index_merge
當(dāng)使用多個條件進行交集或并集時出現(xiàn)。
- range
對索引列進行范圍查找時出現(xiàn),比如between、in、>、<等
explain select * from user where id > 1;
- index
全表掃描,但是只查詢索引列的值,因此只需要掃描索引樹即可。
explain select id from user;
- 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)化。