MySQL查询优化之三:执行计划(Execution Plan)

  • Post author:
  • Post category:mysql


当我们优化一个低性能的SQL时,通常第一件事就是查看执行计划。通过执行计划我们可以查看MySQL是如何处理一个SQL语句的,包括表的连接顺序、预估成本、索引使用情况等。

根据SQL执行计划可以找到性能低下的瓶颈在哪,在不需要重写SQL的情况下,通常SQL性能问题可以分为以下几类:

  • 表的连接没有创建索引,连接效率低下。
  • 表的连接顺序不合适。
  • 表创建了索引,但是mysql却没有使用。

对应的解决方法通常为:

  • 建立合适的索引,提升表连接的速度。
  • 调整表的连接顺序(使用hint或外连接)
  • 排查索引失效的原因,重新收集统计信息,帮助优化器选择更好的执行计划。


目录


一、查看执行计划


1. explain


2. explain extended


3. explain partitions


二、执行计划输出列含义


1. id


2. select_type


3. table_name


4. type


5. possible_keys


6. keys


7. key_len


8.ref


9. rows


10. filtered


11.Extra


一、查看执行计划

1. explain

查看执行计划,最简单的办法就是在SQL前添加explain关键字,explain不仅可以解释select查询,还可以解释delete,insert,update和replace语句,但最常用的场景还是优化select查询:

explain select * from cor_crm_ent;

2. explain extended

在explain后增加extended关键字,mysql会在执行计划中额外增加一列filtered,并且会根据执行计划逆向编译出一个select语句。这个语句是在生成执行计划后,根据执行计划反向编译出来的,与原SQL无关,可以用show warnings语句查看。大部分情况下这个SQL与原SQL不同,可以通过这种方式查看mysql是如何改写SQL语句的。

explain extended select cust_id,company_name from cor_crm_ent;

注意explain extended语句会附带一个warning信息,通过show warnings我们可以查看反向编译的SQL:

show warnings;

3. explain partitions

explain partions可以显示检索的分区信息,这个选项只有在涉及分区表才会使用,普通非分区表即使使用也显示为空

explain partitions select count(*) from focs_interest partition (p_201808);

二、执行计划输出列含义

1. id

select的标识符,一般按select出现的顺序编号。但如果是引用union的结果,id显示为空,此时table列会显示<unionM,N>,代表编号为M和N的select合并结果。

explain 
select * from (     -- id为1的select                    
select cust_id from cor_crm_ent -- id为2的select       
union 
select credit_id from cor_lms_facility) t;  -- id为3的select       

注意最后一行union result,id的编号为空,同时table列是<union2,3>,代表是id为2,3的select合并后的结果集。

2. select_type

select_type代表不同的select类型,具体的值和含义如下表:


select_type


含义


SIMPLE

简单select查询(没有用到union或子查询)

PRIMARY


最外层select。这个类型通常可以在DERIVED和UNION类型混合使用时见到。



UNION


union中第二个以及之后的select

DEPENDENT UNION

union中第二个以及之后的select,且与外层查询关联

UNION RESULT

union的结果

SUBQUERY

子查询中第一个select

DEPENDENT SUBQUERY

子查询中第一个select,且与外层查询有关联

DERIVED

出现在FROM列表中的子查询被标记为DERIVED(衍生表)

MATERIALIZED

物化子查询

UNCACHEABLE SUBQUERY

无法缓存的子查询,外层查询的每一行都要重新计算子查询的值

UNCACHEABLE UNION

UNCACHEABLE SUBQUERY中union查询第二及之后的select

3. table_name

查询用到的表名,也可能是union结果集,衍生表,物化子查询,可能出现的值如下:


table_name


含义


table_name

查询引用的表名

<unionM,N>


id为M和N查询union后的结果



<derivedN>


id为N的衍生表

<subqueryN>

id为N的物化子查询

4. type

数据的访问方法,具体的解释可以参考下面文章:


MySQL查询优化之一:数据的访问方法(Access Paths)_V1ncent Chen的博客-CSDN博客

5. possible_keys

查询中可能用到的索引,这里只是列出可以使用的索引,但实际查询时并不一定会用到。

6. keys

显示MySQL实际使用的索引,如果这个索引没有出现在possible_keys列中,那么MySQL选用它是出于另外的原因——比如它可能选择了一个覆盖索引。

7. key_len

实际使用的索引(keys列)的字节数。

8.ref

显示在key列记录的索引中查找值所用的列或常量。

9. rows

这一列是MySQL估计为了找到所需的行而要读取的行数。数值根据索引和统计信息计算出,可能不是很精确。rows列的值如果很大,通常代表访问方法(type列,access paths)不是很高效,需要尝试是否有更高效的访问方法。

10. filtered

使用explain extended会显示此列,它显示的是针对表里符合某个条件(WHERE子句或联接条件)的记录数的百分比所做的一个估算。如果你把rows列和这个百分比相乘,就能算出MySQL估算它将和查询计划里前一个表关联的行数。

在查看执行计划时,rows*filtered列是一个需要关注的重点,大量的数据会导致连接速度急剧下降。

11.Extra

包含一些不适合在其他列显示额外信息,其中比较重要的有如下(完整的内容较多,可以参考官方文档):


Extra


含义


Using where

MySQL服务器在收到存储引擎的记录后通过where条件进行“后过滤”(MySQL中索引过滤是在存储引擎层,where条件过滤是在应用层)

Using temporary


MySQL将使用临时表来处理结果集,常见于排序和分组查询


(如果无法在内存中建立临时表,建立磁盘临时表成本会很高)


Using filesort

MySQL无法利用索引来完成的排序操作称为filesort(这是一个CPU密集型操作)

可以通过建立合适的索引来消除排序

Using index

索引覆盖,只需要访问索引就可以获取结果,无需回表操作

Using join buffer

连接时没有使用索引,需要连接缓冲区来存储中间结果

考虑添加合适的索引来改进性能

Impossible where

没有符合where条件的记录

Using MRR

使用MRR(Multi-Range Read)优化策略(二级索引随机I/O转化为顺序I/O)

在优化SQL,阅读执行计划时,我们通常需要关注的点有:

  1. table列,关注连接的顺序,驱动表是否高效。
  2. type/possible_keys/key,关注索引的使用情况(SQL的写法、统计信息失效都会导致未正确使用索引)。
  3. rows/filter,关注是否需要访问大量的数据,通常与访问方法type有关,高效的访问方式,rows列值通常都很低。
  4. extra列,辅助判断执行信息,是否有排序(filesort)等高成本操作,考虑用索引消除。

对于也SQL可以尝试优化改写,并查看不同的执行计划区别,找到最高效的方式。



版权声明:本文为frostlulu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。