mysql提供了explain语句,让我们可以查看某个语句的具体执行计划。
explain语句输出中各个列的作用 #
- id。每个select关键字都对应一个唯一的id(语句可能被重写)。
- select_type select关键字对应的查询的类型。
- table 表名。
- partitions 匹配的分区。
- type 针对单表的访问方法。
- possible_keys 可能使用的索引。
- key 实际使用的索引。
- key_len 实际使用的索引的长度。
- ref 当使用索引列等值查询时,与索引列进行等值匹配的对象信息。
- rows 预估需要读取的记录数。
- filtered:针对预估的需要读取的记录,经过搜索条件过滤后剩余记录条数的百分比。
- extra 额外信息。
执行计划输出各列详解 #
table #
输出中的每条记录都对应着某个单表访问方法,该条记录的table列代表该表的表名。
id #
查询语句中每出现一个select关键字,mysql就会为它分配一个唯一的id。 在连接查询的执行计划中,每个表都会对应一条记录,这些记录的id值是相同的;出现在前面的表示驱动表,出现在后面的表表示被驱动表。
对于包含子查询的关键字来说,可能涉及多个select关键字。每个select关键字都会对应一个唯一的id值。
查询优化器可能对涉及子查询的语句进行重写,从而转换为连接查询。
id值为null表名这个临时表是为了合并两个查询的结果集而创建的。
union会把多个查询的结果集合并起来并对结果集中的记录进行去重。
union all不需要对结果集进行去重。
select_type #
mysql为每一个selct关键字代表的小查询都定义了一个名为select_type的属性。只要知道了某个小查询的select_type属性,也就知道了这个小查询在整个大查询中扮演的角色。
此列的值可能是以下几种(列举主要的几种):
- simple 简单查询,语句中不包含union或者子查询的查询都算simple类型。连接查询的select_type也是simple。
- 对于包含union,union all或者子查询的大查询来说,它是由几个小查询组成的;其中最左边的那个查询的select_type的值就是primary。
- union 对于包含union或union的大查询来说,它是由几个小查询组成的,其中除了最左边的那个小查询以为,其余小查询的select_type的值就是union。
- union result mysql使用临时表来完成union查询的去重工作,针对该临时表的查询的select_type就是union result。
- subquery 如果包含子查询的查询语句不能转为对应的半连接形式,并且该子查询是不想管子查询,而且查询优化器决定采用将该子查询物化的方案来执行该子查询时。该子查询的第一个select关键字代表的那个查询的select_type就是subquery。
- materialized 当查询优化器在执行包含子查询的语句时,选择将子查询物化之后与外层查询进行连接,该子查询对应的select_type属性就是materialized。
type #
代表着mysql对某张表执行查询时的访问方法。主要值有以下几种:
- system 表中只有一条记录并且该表使用的存储引擎的统计数据是精确的。
- const 根据主键或者唯一二级索引列与常数进行等值匹配。
- eq_ref 执行连接查询,被驱动表时通过主键或者不允许存储null的唯一二级索引等值匹配的方式进行访问的。
- ref 通过普通二级索引列与常量进行等值匹配的方式来查询。
- fulltext 全文索引。
- ref_or_null 对普通二级索引列进行了等值匹配且该索引列的值夜可能是null,对该表的访问方法就可能是null。
- index_merge 索引合并。
- range 如果使用索引获取某些单点扫描区间的记录,那么就可能用到range访问方法。
- index 可以使用覆盖索引,但需要扫描全部的索引记录。 此外对于innodb存储引擎来说,当我们需要执行全表扫描,并且需要对主键进行排序时,此时type列的值夜是index。
- all 全表扫描。
possible_keys 和key #
possible_keys表示在某个查询中对某张表执行单表查询时可能用到的索引有哪些,key列表示实际使用功能的索引有哪些。 possible_keys中的值并不是越多越好,可以使用的索引越多,查询优化器在计算成本时花费的时间就越长。
key_len #
表示mysql在使用索引时,索引的长度是多少。 计算方法: - 该列的实际数据最多占用的存储空间长度。 - 如果该列可以存储null,则再加1字节。 - 对于变长类型来说,再加2字节。
**执行计划的生成是server层功能。**
ref #
ref列展示的是与索引列进行等值匹配的是什么,比如只是一个常数或者某个列。
rows #
如果决定使用全表扫描,rows就代表该表的估计行数。
如果使用索引来执行查询,rows就代表语句扫描的索引技术行数。
filter #
查询优化器预测的rows中满足条件的记录的比例。
extra #
- using index 使用了覆盖索引。
- using index condition 索引条件下推。有些搜索条件虽然出现了索引列,但却不能充当边界条件来形成扫描区间,也就是不能用来较少扫描的记录数,将会提示该额外信息。 mysql会把扫描条件放在引擎层进行过滤,从而避免了回表。
- using where 某个搜索条件需要再server层进行判断。
- using join buffer 连接查询,被驱动表不能有效地利用索引加快访问速度时,mysql一般会为其分配一块名为连接缓冲区的内存来加快查询。
- using filesort 排序无法使用到索引,只能在内存或磁盘中进行排序。
- using tempporary 临时表。mysql可能会借助临时表来完成一些功能,比如去重、排序等。 mysql会在包含group by子句的查询中默认添加order by子句。
json格式的执行计划 #
可以在explain和查询语句之间加上format=json来获取json格式的执行计划,查看某个执行计划的查询成本。 其中部分字段:
cost_info:
查询成本信息。字段列表如下:
- read_cost:读取成本。I/O成本+CPU成本。
- eval_cost:检测过滤记录的成本。
- prefix_cost:单独查询x表的成本。
- data_read_per_join:单词查询需要读取的数据量。
注意:在连接查询中,被驱动表可能被读取多次。