介绍
explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。
使用方法,在select语句前加上explain就可以了(MySQL 5.6开始,不仅仅支持select )
各列含义详解
id
标识select,id列数字越大越先执行,如果说数字一样大,那么就从上往下依次执行,id列为null的就表是这是一个结果集,不需要使用它来进行查询。
select_type
用来表示查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询。
常用的值:SIMPLE:简单 SELECT (不使用 UNION 或子查询)
PRIMARY:最外面的 SELECT
UNION:UNION 中的第二个和随后的 SELECT 语句
DEPENDENT UNION: UNION 中的第二个或后面的 SELECT 语句,取决于外面的查询
UNION RESULT: UNION 的结果
SUBQUERY:子查询中的第一个 SELECT
DEPENDENT SUBQUERY:子查询中的第一个 SELECT ,取决于外面的查询
DERIVED:导出表(派生表)的 SELECT ( FROM 子句的子查询)
UNCACHEABLE SUBQUERY:子查询中的第一个 select 语句,同时意味着 select 中的某些特性阻止结果被缓存于一个 Item_cache 中
UNCACHEABLE UNION:满足此查询是 UNION 中的第二个或者随后的查询,同时意味着 select 中的某些特性阻止结果被缓存于一个 Item_cache 中
例:简单子查询
from 子句中的子查询
UNION 查询
table输出的行所引用的表
显示的查询表名,如果查询使用了别名,那么这里显示的是别名,如果不涉及对数据表的操作,那么这显示为 null,如果显示为尖括号括起来的 就表示这个是临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生。如果是尖括号括起来的,与 类似,也是一个临时表,表示这个结果来自于union查询的id为M,N的结果集。
type依次从好到差:system > const > eq_ref > ref > fulltext > ref_or_null > unique_subquery > index_subquery > range > index_merge > index > ALL
除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一个索引
最常用的从好到差依次是:system > const > eq_ref > ref > range > index > all
一般来说,得保证查询至少达到range级别,最好能达到ref。
system :表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计
const :表示通过索引一次就找到了,const用于比较primary key 或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,MySQL就能将该查询转换为一个常量。
eq_ref :唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。使用这种索引,MySQL知道最多只返回一条符合条件的记录。
ref :它是一种索引访问(有时也叫做索引查找),它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。把它叫做ref是因为索引要跟某个参考值相比较。此类索引访问只有当使用非唯一性索引或者唯一索引的非唯一性前缀时才会发生。
range :范围扫描就是一个有限制的索引扫描,key列显示使用了哪个索引,一般就是在你的where语句中出现between、< 、>、in等的查询,这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
index :这个跟全表扫描一样,只是MySQL扫描表时按索引次序进行而不是行。它的主要优点是避免了排序;最大优点是要承担按索引次序读取整个表的开销。如果在EXTRA列中看到using index,说明MySQL正在使用覆盖索引,它比按索引次序全表扫描的开销要少的多。
all :全表扫描,将遍历全表以找到匹配的行
possible_keys
查询可能使用到的索引都会在这里列出来
key
查询真正使用到的索引,select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个。
key_len
用于处理查询的索引长度,单位为字节,如果是单列索引,那就整个索引长度算进去,如果是多列索引,那么查询不一定都能使用到所有的列,具体使用到了多少个列的索引,这里就会计算进去,没有使用到的列,这里不会计算进去。留意下这个列的值,算一下你的多列索引总长度就知道有没有使用到所有的列了。要注意,mysql的ICP特性使用到的索引不会计入其中。另外,key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中。
例:
主键(actor_id,film_id)是两个SMALLINT列,每个SMALLINT是2字节,那么索引中的每项是4个字节,key_len中显示使用的索引长度为2,可以推断出只使用了actor_id列,来执行索引查找。
这个查询中key_len为13个字节,即为a列和b列的总长度,a列是三个字符,utf8下每个字符最多3个字节,b列是一个4字节整型。
ref
显示使用哪个列或常数与key一起从表中选择行。
rows
这里是执行计划中估算的扫描行数,不是精确值
extraUsing filesort(九死一生):说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序”。
Using temporary(十死无生):使用了用临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。
Using index(发财了):表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错。如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
Using where :表明使用了where过滤
Using join buffer :表明使用了连接缓存,比如说在查询的时候,多表join的次数非常多,那么将配置文件中的缓冲区的join buffer调大一些。
impossible where :where子句的值总是false,不能用来获取任何元组
select tables optimized away :在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
distinct :优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作
一个复杂 SELECT 类型的例子
explain 结果:
结果集中第1行使用了 from 子查询的临时表 der_1,这个子查询被标记为。
第 2 行id为 3,因为它是查询中第3个select的一部分,归为DERIVED的原因是它嵌套在from子句中。
第 3 行id为 2,它排在id为3的后面,因为它比 id 为 3 的 select 后执行,它依赖于id为3的查询,所以被归为DEPENDENT SUBQUERY。
第 4 行 id 为4,被归为UNION,意味着它是UNION中第2个或之后的select,它的表为,说明它使用的是从from子查询中的临时表。
第 5 行的 id 为 6,是 from 中的子查询,类型为 DERIVED。
第 6 行 id 为 7,是的select列表中的一个普通子查询。
第 7 行 id 为5,因为有用户变量,它被列为UNCACHEABLE SUBQUERY
最后一行是 UNION RESULT。