vlambda博客
学习文章列表

MySQL中SQL语句的执行计划,你理解了吗?

首先我们来看一下什么是执行计划:

  执行计划就是解释select语句如何在数据库执行的、相关表是怎么连接、连接的次序、有哪些索引和索引使用、每个表的扫描数据量等等。简单来说,就是通过数据来分析select语句的执行情况;

  怎么查看执行计划:查看执行需要用到关键字EXPLAIN,将EXPLAIN放在SQL语句的前面( EXPLAIN [EXTENDED] SELECT select_options ),如下图:

  

  从上图可以看出,通过执行计划展示了表格数据,这个表格有id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、extra等字段的信息,这些字段分别表示什么意思呢?下面具体介绍下:

  1、id

  执行计划的id 是select查询的序列号,标识执行顺序。注意有两种情况,具体如下:

  1)、当id相同时,执行顺序从上到下执行。

  左外连接,先执行左边后执行右边(例如:select * from user u left join custom_order co on u.id=co.creater 会先执行user表后执行custom_order),在执行计划中,user表应该在上面,custom_order在下面,如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  右外连接,先执行右边后执行左边(例如:select * from user u right join custom_order co on u.id=co.creater 会先执行custom_order表后执行user表),在执行计划中,custom_order表应该在上面,user在下面:

  MySQL中SQL语句的执行计划,你理解了吗?

  从上面的执行结果来看,和预计的一样。

  2)、当id不相同时,id越大越先执行。

  例如:select * from user where id=(select creater from custom_order where id=1),这个语句中的子查询会比主查询会先执行。那在explain select * from user where id=(select creater from custom_order where id=1) 中 custom_order 的id应该是2,user的id应该是1,实际是不是这样呢,如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  从结果中可以知道,执行结果和预计的一样;

  2、select_type

  执行计划的select_type是select语句的类型,用于区分各种查询;具体类型有以下几种:

  1)、SIMPLE

  简单的select语句,不使用union或子查询。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  2)、PRIMARY

  最外层的select语句。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  3)、UNION

  union中的第二个或后面的select语句。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  4)、DEPENDENT UNION

  union中的第二个或后面的select语句,取决于外面的查询。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  5)、UNION RESULT

  union的结果。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  6)、SUBQUERY

  子查询的第一个select语句。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  7)、DEPENDENT SUBQUERY

  子查询中的第一个select语句,取决于外面的查询。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  8)、DERIVED

  衍生表的select语句(在from列表中包含的子查询)。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  3、table

  语句查询中所涉及到的表。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  4、partitions

  查询涉及到的分区。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  MySQL中SQL语句的执行计划,你理解了吗?

  5、type

  SQL语句的连接类型。具体个连接类型如下:(按照从效率高的类型到效率低的类型进行排序)

  1)、system

  表仅有一行(等于系统表)。这是const连接类型的一种特例。

  2)、const

  表最多有一个匹配行,它将在查询开始时被读取,常用于主键或唯一索引的定值查询。因为匹配行只有一行,所以查询速度很快。如下图(id是主键):

  MySQL中SQL语句的执行计划,你理解了吗?

  3)、eq_ref

  唯一性索引扫描,对于前表的每一行,表中只有一行与之相匹配或者没有能匹配。常见于主键或唯一索引扫描。是除const类型和system类型外最快的类型。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  4)、ref

  非唯一性索引扫描,对于前表的每一行,表中可存在多个与之相匹配的行。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  5)、ref_or_null

  和ref类型一样,但是添加了mysql可以专门搜索包含NULL值的行。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  6)、index_merge

  标识使用了索引合并优化方法。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  7)、unique_subquery

  一个索引查找函数,可以完全替换子查询,效率更高。

  8)、index_sugquery

  类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引。

  9)、range

  只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  10)、index

  扫描索引树。如果索引是复合索引,并且复合索引列满足select所需的所有数据,则仅扫描索引树,不需要回表。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  11)、ALL

  扫描全表。这是最差的情况,没有索引,进行完整的表扫描。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  6、possible_keys

  语句中能使用索引有哪些。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  7、key

  该语句执行的时候是使用的哪条索引。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  8、key_len该语句执行时使用的索引长度(字节数)。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  9、ref

  该表的索引字段关联了哪张表的哪个字段。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  10、rows

  该语句执行时需要读取行数,数越小越好。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  11、filtered

  该语句返回结果的行数占读取行数的百分比,值越大越好。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  12、extra

  十分重要的额外信息。常见的如下:

  1)、Distinct

  MySQL发现第一个匹配的行后,停止为当前索引搜索更多的行。

  2)、Not exists

  MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的索引在该表内检查更多的行。

  MySQL中SQL语句的执行计划,你理解了吗?

  3)、Using filesort

  MySQL 对数据使用一个外部的文件内容进行了排序,而不是按照表内的索引进行排序读取。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  4)、Using index

  仅使用索引树中的信息从表中检索列信息,而不必另外寻找读取实际行,即不需要回表。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  5)、Using temporyary

  在查询时,MySQL需要创建一个临时表来保存结果。常出现使用GROUP BY和ORDER BY子句时。如下图:

  MySQL中SQL语句的执行计划,你理解了吗?

  6)、Using where

  在查找使用索引的情况下,需要回表去查询所需的数据,后再用WHERE子句完成结果过滤,通常出现这种情况的话就需要添加合适的索引来做优化了。如下图:

  

  7)、Using join buffer

  连接中的表分成几部分读入连接缓冲区,然后从缓冲区中使用它们的行来与当前表执行连接。如下图: