文章目录
- 1、概述
- 2、作用
- 3、字段详解
- 3.1、id
- 3.2、select_type
- 3.3、table
- 3.4、partitions
- 3.5、type
- 3.6、possible_keys
- 3.7、key
- 3.8、key_len
- 3.9、ref
- 3.10、rows
- 3.11、filtered
- 3.12、Extra
我的MySQL版本为5.7,不同版本结果可能略有差异
官方文档地址:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
1、概述
用 EXPLAIN 关键字可以模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理你的 SQL 语句的。分 析你的查询语句或是表结构的性能瓶颈。
使用方式:Explain + SQL语句
2、作用
- SQL执行时,表的读取顺序
- 数据读取操作的操作类型
- 哪些索引能够被使用的,哪些索引是真实被使用的
- 表与表之间的引用关系
- 每张表有多少行能被优化器优化
3、字段详解
3.1、id
select查询的序列号,包含一组数字,表示查询中执行select语句或者操作表的顺序。
id大小相同,执行顺序由上至下
当执行结果的id相同时,表示MySQL在分析执行我们的SQL语句时,其执行顺序为由上至下。即例子中,先执行表e的操作,再执行表d的操作。
id大小不同,id值越大优先级越高,越先执行
当执行结果的id不同时,id值越大,执行的优先级越高。即例子中,会先执行表d的操作,然后再去执行表e的操作。
id大小既有相同,又有不同。规则同上
在前面两个的基础上,这个也就不难理解了。先执行表t_tag的操作,然后执行表e的操作,最后是表d的操作。
3.2、select_type
查询的类型:主要用于区分此次的查询,属于什么类型,普通查询?子查询?嵌套查询?
常见的属性值,及其含义
- SIMPLE:简单的select查询,查询中不包含子查询或者union;
- PRIMARY:查询中若包含任何复杂的子部分,最外层查询则会被标记为primary;
- SUBQUERY:在select或者where列表中包含了子查询;
- DERIVED:在from列表中包含的子查询被标记为derived(衍生),MySQL会递归执行这些子查询,把结果放在临时表中;
- UNION:若第二个select出现在union之后,则会被标记为union;若union包含在from子句的子查询中,外层select将被标记为:derived;
- UNION RESULT:从union表获取结果的select
- DEPENDENT SUBQUERY:
- DEPENDENT UNION:
各类型说明
PRIMARY、SUBQUERY、SIMPLE
- e表:我们可以发现,在where条件后面,使用了e表的deptId字段进行子查询。同时,表e所在的位置为嵌套的最外层,即查询类型完全符合primary的规则,所以类型为primary(如果没有where后面的条件过滤,该次查询的类型就是simple)
- d表:subquery与primary的主要区别为,在都含有子查询的基础上,观察该表所处的位置。如果是最外层就是primary,否则就是subquery。此处我们的d表为内嵌在e表的子查询中,符合subquery的规则。
DERIVED、UNION、UNION RESULT
补充:上面的SQL查询也是MySQL的7种经典连接之一,如下图:
- d2、e2表:由前文的id大小可知,最开始的两次表操作为操作表d2,再操作表e2。我们发现该表的查询位置位于union关键字之后,所以它对应的查找类型为union。
- d、e表:derived表示临时表,这两个表位于from关键字之后。d表和e表都在from关键字后面,即对于from括号后面的数据集,我们可以将他想象成一个临时表,所以它对应的查找类型也就是derived。
小插曲:本人MySQL版本5.7,网上找资料的时候,它们很多人在第一种情况时就能出现derived查找类型。但是我测试了好久都不行(图1),但如果对后面的临时表进行了相关的操作(图2 3),就会出现derived关键字的查找类型。网上相关博客的记录都没有说明MySQL的版本,所以我大胆的假设一下,在MySQL5.7,对derived临时表的出现进行了优化
- <derived2>表:该表为临时表,id最小为1,即表示该SQL的最后一步操作。最后一步操作,由于该查询包含了复杂的子句,注定其查询条件只能是一个primary
- <union2,3>表:此次操作为连接id为2和3的结果集。所以查找的类型为union result
3.3、table
该列表示此次操作的对象是哪一个表。
3.4、partitions
如果查询是基于分区表的话,会显示对应的分区信息。如果不是分区表,比如我们这里,它就是null。
3.5、type
此次查询,使用了什么类型
常见属性值,及其含义
- ALL:Full Table Scan,遍历全表用于查找匹配的行。
- INDEX:Full Index Scan,index和all的区别为index类型只遍历索引树(可以理解为只查询索引列),这通常比all来的快。因为索引文件通常比数据文件小。
- RANGE:只检索给定范围的行,使用一个索引来选择行。索引列显示的使用。如果在where条件后出现了between、<、>、in等关键字的查询,就会出现该种类型。这种范围的索引扫描要比全表扫描好,因为它只需要开始于索引的某一个点,而结束于另一个点,不需要全表扫描。
- REF:非唯一性索引扫描,返回匹配某个单独值的所有行。其本质上也是一种索引访问,但是能与该索引字段匹配的数据,不止一行。
- EQ_REF:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。读取本表中和关联表表中的每行组合成的一行,当连接使用索引的所有部分时, 索引是主键或唯一非 NULL 索引时, 将使用该值。即这种类型常出现在join查询中
- CONST:表示通过一次索引就可以找到,const常用于比较primary key或者unique索引,因为它们只需要匹配一行数据,所以查询的速度很快。如将主键字段作为查询条件,MySQL就能够将此次的查询转换为一个常量。
- SYSTEM:表只有一行记录(等于系统表),这是const类型的一个特例,平时很少出现,可以忽略不计。
查询效率由高到低分别是:
完整版:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > uniqe_subquery > index_subquery > range > index > all
精简版:system > const > eq_ref > ref > range > index > all
一般SQL被优化到range级别即可,最好能到达ref。切记,不要为了优化而优化
举例说明
该字段的含义比较简单,即代表在此次查询中,使用了什么类型。属于如果是最简单的select * from table 那就是一个全表扫描,其对应的类型就是all。同理,只要满足range属性出现的条件,该属性值就会是range,如下:
注意,id字段是主键,所以就自带了唯一索引。type的很多属性值的前提条件,都是针对索引列才有效的。
3.6、possible_keys
显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被实际使用。
例如,我给test表新建了一个唯一索引和普通索引,加上test表的id字段是主键,那么它还会有一个主键索引。这样就是三个索引,即我们的possible_keys就会有三个值
3.7、key
在上面possible_key的基础上,key表示真实用到的索引。
在possible_key的举例中,我们发现key的属性值为primary,即表示我们此次的查询中,真正使用到的索引类型是主键索引。
如果查询中出现了覆盖索引,则索引列仅出现在key列表中。如:
我们的id列是索引列,由于查询的字段仅包含索引列,所以满足我们查询中出现了覆盖索引。以至于我们的possible_keys列中没有值,表示此次查询可使用的索引为0,但是真实在查询时却使用到了唯一索引。(如果我们这里没有新建索引,那么这个字段的属性就会是primary)
该属性值可以用来帮我们分析一下查询中的一些特殊情况,比如索引失效。
3.8、key_len
该列主要表示索引的字节的长度。在不损失精度的情况下,数字越小越好。其显示的值为索引字段的最大可能长度,而非实际使用的长度,即key_len是根据表定义计算得到的,而不是通过表内的检索得出的。
计算该长度相关注意事项:
- int类型占4个字节
- 在UTF8的字符集中,一个字符占用3个字节。char为3n,varchar为3n+2
- datetime类型占用3个字节
- 如果字段可以为null,会比字段不能为null多一个。会多出一个字节用来维护数据可以为null
3.9、ref
表示上述表的连接匹配条件,哪些列或常量被用于查找索引列上的值。显示索引的哪一列被使用了,如果可能的话是一个常数。
在使用索引的时候,会用哪几个值去索引中找对应的数据,这里的哪几个值,指的就是被索引引用到的值。
显示了在key列记录的索引中查找值所用的列或常量,值为null时仅表示啥都没使用。
示例:
3.10、rows
表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
参考ref中的例子。我们在对e表进行查询时,由于使用到了主键索引,即数据唯一,所以我们最终所需要的行也就是一行。
3.11、filtered
MySQL5.7之后的版本,默认就有这个字段。这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的百分比。
3.12、Extra
包含不合适在其他列中展示,但是十分重要的额外信息
属性值及其含义
- Using filesort:MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作,称为”文件排序“(索引本身有序,排序时如果没有使用到它,就会产生。常见于排序order by 和分组查询group by语句中)
- Using temporary:使用了临时表保存中间结果,MySQL在对查询结果排序时使用到了临时表。
- Using index:表示响应的查询操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率很高。如果同时出现了Using where,表明索引被用来执行索引键值的查找;如果没有同时出现Using where,表明索引用来读取数据而非执行查找动作。
- Using where:使用了where条件进行过滤
- Using join buffer:使用了连接缓存
- Impossible where:where子句的值总是false,无法获取到任何元素(where id= 1 and id = 2)
- Select tables optimized away:在没有group by子句的情况下,基于索引优化的min/max操作或者对于MyISAM存储引擎优化count(*) 操作,不必等到执行阶段在进行计算,查询执行计划生成阶段即完成优化
- Distinct:优化distinct操作,在找到第一个匹配的元组后即停止找同样值得动作