mysql-EXPLAIN
先看看使用explain执行查询语句显示的列
1、id列:
id相同,执行顺序由上至下
如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行。
id如果相同,可以认为是一组,从上往下顺序执行,在所有组中,id值越大优先级越高,越先执行。
2、select_type列:
这一列显示了对应行是简单还是复杂SELECT(如果是复杂SELECT,那么是三种复杂类型中的哪一种)。SIMPLE值意味着查询不包括子查询和UNION。如果查询有任何复杂的子部分,则最外层部分标记为PRIMARY,其他部分标记如下:
SUBQUERY: 在SELECT 或 WHERE 中包含子查询
explain select * from role_permission where role_id = (select id from role where name='管理员');
DERIVED: DRIVED值用来表示包含在FROM字句的子查询的SELECT,MySQL会递归执行并将结果放到一个临时表中。服务器内部称其“派生表”,因为该临时表是从子查询中派生来的。
explain select role_id from (select * from role_permission) rp
UNION:UNION中第二个或后面的SELECT语句
explain select * from role_permission where role_id=28 union select * from role_permission;
UNION RESULT:用来从UNION的匿名临时表检索结果的SELECT被标记为UNION RESULT
3、table列
这一列显示了对应行正在访问哪个表。可以在这一列从上往下观察MySQL的关联优化器为查询选择的关联顺序。可以从下面的查询中MySQL选择的关联顺序不同于语句中所指定的顺序。
EXPLAIN SELECT film_id FROM film INNER JOIN film_actor USING(film_id) INNER JOIN actor USING(actor_id);
MySQL的查询执行计划总是左侧深度优先树。如果把这个计划放倒就能按顺序读出叶子节点
4、type列
MySQL在表中找到所需行的方式。常用的类型有:
ALL、index、range、ref、eq_ref、const,system、NULL(从左到右,性能从差到好)
ALL:Full Table Scan 全表扫描,以为着MySQL必须扫描整张表,从头到尾,去找到需要的行。(这里也有例外,例如在查询里使用了LIMIT,或者在Extra列中显示“Using distinct/not exists”)
index:Full Index Scan 这个跟全表扫描一样,只是MySQL扫描表时按索引次序进行而不是行。它的主要优点是避免了排序,最大的缺点是要承担按索引次序读取整个表的开销。这通常意味着若是按随机次序访问行,开销将会非常大。如果在Extra列中看到“Using index”,说明MySQL正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行。它比按索引次序全表扫描的开销要少很多。
range:范围扫描就是一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这个值域的行。这比全索引扫描好一些,因为它用不着遍历全部索引。显而易见的范围扫描是带有BETWEEN或WHERE子句里带有">"的插叙。当MySQL使用索引去查找一系列值时,例如IN()和OR列表,也会显示为范围扫描。然而,这两者其实是相当不同的访问类型,在性能上有重要的差异。次类扫描的开销跟索引类型相当。
ref:表示上述表的连接匹配条件,即那些列或常量被用于查找索引上的列。他返回所有匹配某个单个值的行。然而,它可能会找到多个符合条件的行,因此它是查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。把它叫做ref是因为索引要跟某个参数值相比较。这个参考值或者是一个常数,或者是来自多表查询前一个表里的结果值。ref_or_null是ref之上的一个变体。它意味着MySQL必须在初次查找的结果里进行第二次查找以找出NULL条目。
eq_ref:类似于ref,区别是使用的索引是唯一索引,对于每个索引健值,表中只有一条记录匹配,简单来说就是多表连接中使用primary key 或者 unique key作为关联条件
const、system:当MySQL对查询某部分进行优化并转换为一个常量时,使用这些类型访问。如将主键至于where列表中。MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system。
NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引里选取最小值可以通过单独索引查找完成。
例如:doctor表的primary key 是ID
explain select * from doctor WHERE ID in(1,2,3);
explain select * from doctor WHERE hospital_id in(1,2,3);
explain select * from doctor WHERE ID BETWEEN 1 AND 3;
例如:doctor表的ID是主键
EXPLAIN select hospital_id from doctor WHERE ID=2;
EXPLAIN select ID, hospital_id from doctor WHERE ID=2;
EXPLAIN select ID from doctor WHERE ID=2;
5、possible_keys列:
这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程时没用的。
6、key列:
这一列显示了MySQL决定采用哪个索引来优化对该表的访问。如果索引没有出现在"possible_keys"列中,那么MySQL选用它是处于另外的原因。--例如,它可能选择了一个覆盖索引,哪怕没有WHERE子句
7、key_len列:
这列显示了MySQL在索引里使用的字节数。
8、ref列:
这一列显示了之前的表在key列记录的索引中查找值所用的列或常量。
9、rows列:
这一列是MySQL估计为了找到所需的行而要读取的行数。这个数字是内嵌循环关联计划里的循环数目。也就是说它不是MySQL认为它最终从表里读取出来的行数,而是MySQL为了找到符合查询的每一点上标准的那些行而必须读取的行的平均数。
10、filtered列:
这个列在使用“EXPLAIN EXTENDED”时出现。它显示的是针对表里符合某个条件(WHERE子句或联接条件)的记录数的百分比所做的一个悲观估算,优化器只有在使用ALL、index、range、index_merge访问方法时才会用这一估算。
11、Extra列:
这一列包含的是不适合在其他列的额外信息。
"Using index" 表示MySQL将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
“Using where”这意味着MySQL服务器将在存储引擎检索行后再进行过滤。许多WHERE条件里涉及索引中的列,当它读取索引时,就能被存储引擎检验,因此不是所有带WHERE子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
“Using temporary”这意味着MySQL在对查询结果排序时会使用一个临时表。
“Using filesort”这意味着MySQL会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。
“Range checked for each record(index map:N)”这个值意味着没有好用的索引,新的索引将在联接的每一行上重新估算。N是显示在possible_keys列中索引的位图,并且是冗余的。
参考:
【1】Baron Schwartz等 著,宁海元等 译 ;《高性能MySQL》(第3版); 电子工业出版社 ,2013
【2】博客,http://blog.csdn.net/zhuxineli/article/details/14455029
【3】MySQL执行计划解读,https://yq.aliyun.com/articles/364570