通过EXPLAIN + SQL语句 可以查看SQL语句的执行计划,
例如:

  1. EXPLAIN SELECT
  2. store_id,
  3. film_id
  4. FROM
  5. inventory
  6. WHERE
  7. store_id = 1;

查询结果可能是这样的:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE inventory
ALL



4581 10 Using where

下面解释一下执行计划中每一列字段分别的含义。

id

查询编号,如果没有子查询或者联合查询的话,就只有一条,如果是联合查询的话,那么就会出现一条id为null的记录,并且标志查询结果,因为union结果会放到临时表中。
image.png

select_type

查询类型,决定访问表的方式。

思维导图

MySQL执行计划详解 - 图3

SIMPLE

简单查询,代表没有子查询或者union。

PRIMARY

主查询,如果不是简单查询,那么最外层查询就会标记为PRIMARY

UNION & UNION RESULT

如下图,联合查询,第一个查询会被标记为PRIMARY,UNION之后的查询被标记成了UNION,最后产生的结果标记为UNION RESULT
image.png

DERIVED

用于标记在from里面出现的子查询,这个结果会放到临时表中,如下图。
image.png
但是,mysql5.7针对于5.6版本做了一个优化,针对mysql本身的优化器增加了一个控制优化器的参数叫 derived_merge 派生类合并)。
image.png
通过这个优化,你写了from子查询相当于没写。执行计划就会变成这样。
image.png
如果你的MySQL版本比较高级,参数调整设置如下:

  1. -- 会话级别设置derived_mergeonoff
  2. SET SESSION optimizer_switch = 'derived_merge=on/off';
  3. -- 全局级别设置derived_mergeonoff
  4. SET GLOBAL optimizer_switch = 'derived_merge=on/off';

SUBQUERY

不在from里面的子查询。
image.png

DEPENDENT

关联子查询(子查询使用了外部查询包含的列),可以和UNIONSUBQUERY组合产生不同的结果。
image.png

UNCACHEABLE

不能缓存的子查询,也可以和UNION,SUBQUERY组合产生不同的结果。
image.png

MATERIALIZED

物化子查询是MySQL对子查询的优化,第一次执行子查询时会将结果保存到临时表,物化子查询只需要执行一次。
比如上述DERIVED就是物化的一种体现,与之对应的就是DEPENDENT,每次子查询都需要重新调用。
这个结果无法直观的看出来,可以用FORMAT=JSON命令查看materialized_from_subquery字段。
image.png

table

显示表名,从上述的图中可以看出UNION_RESULT和DERIVED显示的表名都有一些命名规则。
比如 UNION_RESULT 产生的是

prtitions

数据的分区信息,没有分区可以忽略。

type

关联类型,决定通过什么方式找到每一行数据。按照效率从快到慢如下
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > ALL

思维导图

MySQL执行计划详解 - 图12

system & const

这通常是最快的查找方式,代表MySQL通过优化最终转换成常量查询,最常规的做法就是直接通过主键或者唯一索引查询。
WeChat Image_20210820134151.jpg
而system是const的一个特例(只有一行数据的表),随便找一张表,只新增一条数据就可以看到system了。
WeChat Image_20210820134248.jpg

eq_ref

通常通过主键索引或者唯一索引查询时会看到eq_ref,它最多只返回一条数据。user_id是唯一索引,为了测试就关联以下主键索引。
image.png

ref

也是通过索引查找,但是和eq_ref不同,ref可能匹配到多条符合条件的数据,比如最左前缀匹配或者不是主键和唯一索引。
最简单的办法,随便查一个普通索引就可以看到。
image.png

fulltext

使用FULLTEXT索引


ref_or_null

和ref类似,但是还要进行一次查询找到NULL的数据。
这相当于是对于IS NULL查询的优化,如果表数据量太少的话,你或许能看到这里类型是全表扫描。
image.png

index_merge

索引合并是在Mysql5.1之后引入的,就像下面的一个OR查询,按照原来的想法要么用name的索引,要么就是用age的索引,有了索引合并就不一样了。
对于这种单表查询(无法跨表合并)用到了多个索引的情况,每个索引都可能返回一个结果,Mysql会对结果进行取并集、交集,这就是索引合并了。

image.png

unique_subquery

按照官方文档所说,unique_subquery只是eq_ref的一个特例,对于下图中这种in的语句查询会出现以提高查询效率。
由于Mysql会对select进行优化,基本无法出现这个场景,只能用update这种语句了。
image.png

index_subquery

和unique_subquery类似,只是针对的是非唯一索引。
image.png

range

看名字就知道,范围查询,其实就是带有限制条件的索引扫描。
常见的范围查询比如between and,>,<,like,in 都有可能出现range。
image.png

index

跟全表扫描类似,只是扫表是按照索引顺序进行。

ALL

全表扫描,没啥好说的。

possible_keys

可能使用到的索引列表。

key

实际使用到的索引。

key_len

索引字段可能的最大长度,不是表中实际使用数据的长度。

ref

表示key展示的索引实际使用的列或者常量。

rows

查询数据需要读取的行数,只是一个预估的数值,但是能很直观的看出SQL的优劣了。

filtered

5.1版本之后新增字段,表示针对符合查询条件的记录数的百分比估算,用rows和filtered相乘可以计算出关联表的行数。

Extra

解析查询的附加额外信息,常见的信息如下:
Using index
使用覆盖索引。
Using index condition
使用索引下推,索引下推简单来说就是加上了条件筛选,减少了回表的操作。
Using temporary
排序使用了临时表。
Using filesort
使用外部索引文件排序,但是不能从这里看出是内存还是磁盘排序,我们只能知道更消耗性能。
Using where
使用where过滤。
Zero limit
除非你写个LIMIT 0。
Using sort_union(), Using union(), sing intersect()
使用了索引合并,参看上文。