一、简介
explain命令用于分析单条SQL语句,是查看优化器如何决定执行查询的主要方法。
要使用EXPLAIN,只需在查询中的SELECT关键字之前增加EXPLAIN这个词。MySQL会在查询上设置一个标记。当执行查询时,这个标记会使其返回关于在执行计划中每一步的信息,而不是执行它。它会返回一行或多行信息,显示出执行计划中的每一部分和执行的次序。
如:
mysql> explain select id from a where id =3\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: a
type: ref
possible_keys: id
key: id
key_len: 5
ref: const
rows: 1
Extra: Using where; Using index
1 row in set (0.00 sec)
注意:认为增加EXPLAIN时MySQL不会执行查询,这是一个常见的错误。事实上,如果查询在FROM子句中包括子查询,那么MySQL实际上会执行子查询,将其结果放在一个临时表中,然后完成外层查询优化。
这意味着如果语句包含开销比较大的子查询或使用临时表算法的视图,实际上会给服务器带来大量工作。
1、id
一个编号,标志SELECT所属的行。如果在语句当中没有子查询或联合,那么只会有唯一的SELECT,于是每一行都将显一个1。否则,内层的SELECT语句一般会顺序编号,对应于其在原始语句中的位置。
MySQL将SELECT查询分为简单和复杂类型,复杂类型可以分为三大类:简单子查询、所谓的派生表(在FROM子句的子查询)、UNION查询。
例(我们只看返回多少行数据就行,其它列先不用理):
# 例1:简单子查询
mysql> explain select (select 1 from a limit 1) from b;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | PRIMARY | b | index | NULL | age | 2 | NULL | 4 | Using index |
| 2 | SUBQUERY | a | index | NULL | PRIMARY | 4 | NULL | 4 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
2 rows in set (0.00 sec)
# 例2:FROM子句中的子查询
mysql> explain select name from (select name from a) as aa;
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| 1 | PRIMARY | | ALL | NULL | NULL | NULL | NULL | 4 | |
| 2 | DERIVED | a | ALL | NULL | NULL | NULL | NULL | 4 | |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
2 rows in set (0.00 sec)
# 例3:UNION查询
mysql> explain select id from a union select id from b;
+----+--------------+------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | PRIMARY | a | index | NULL | PRIMARY | 4 | NULL | 4 | Using index |
| 2 | UNION | b | index | NULL | PRIMARY | 4 | NULL | 4 | Using index |
| NULL | UNION RESULT | | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+------------+-------+---------------+---------+---------+------+------+-------------+
3 rows in set (0.00 sec)
注意UNION结果输出中的额外行。UNION结果总是放在一个匿名的临时表中,之后MySQL将结果取到临时表外。临时表并不在原SQL中出现,因此它的id列是NULL。
2、select_type
显示对应和行是简单还是复杂SELECT(如果是后者,那么一三种复杂类型中的哪一种)。
SIMPLE值意味着查询不包括子查询和UNION。如果查询中有任何复杂的子部分,则最外层标记为PRIMARY,其它标记如下:
1)SUBQUERY
包含在SELECT列表中的子查询中的SELECT(换句话说,不在FROM子句中)标记为SUBQUERY。
2)DERIVED
包含在FROM子句的子查询中的SELECT,MySQL会递归执行并将结果放到一个临时表(服务器内部称其“派生表”)。
3)UNION
UNION中的第二个和随后的SELECT被标记为UNION。
4)UNION RESULT
用来从UNION的匿名临时表检索结果的SELECT被标记为UNION RESULT。
3、table
这一列显示了对应正在访问哪个表。通常情况下,它相当明了:它就是那个表,或者是该表的别名。
4、type
MySql用户手册上说这一列显示了“关联关类型”,但我们认为更准确的说法是访问类型——换言之就是MySQl决定如何查找表中的行。下面是最重要的访问方法,依次从最差到最优。
5、possible_keys
这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程是没用的。
6、key
这一列显示了MySQL决定采用哪个索引来优化对该表的访问。如果该索引没有出现在possible_keys列中,那么MySQL选用它的另外的原因——例如,它可能选择了一个覆盖索引,哪怕没有WHERE子句。
换句话说,possible_keys提示了哪一个索引能有助于高效地行查找。而key显示的是优化采用哪一个索引可以最小化查询成本。
7、key_len
该列显示了MySQL在索引里使用的字节数。如果MySQL正在使用的只是索引里的某些列,那么就可以用这个值来算出具体是哪些列。
8、ref
这一列显示了之前表在key列记录的索引中查找值所用的列或常量。
9、 rows
MySQL估计为了找到所需的行而需要读取的行数。
10、filtered
这一列是在MySQL 5.1里新加进去的,在使用EXPLAIN EXTENDED时出现。它显示的是针对表里符合某个条件(WHERE子句或联接条件)的记录数的百分比所做的一个悲观估算。如果你把row列和这个百分比相乘,就能看到MySQL估算它将和查询计划里前一个表关联的行数。
11、Extra
这一列包含的是不适合在其它列显示的额外信息。常见的最重要的值如下:
《高性能MySQL》 [美]Baron Scbwartz, Peter Zaitsev, Vadim Tkacbenko 著