Explain执行计划

1、explain的基本介绍

有时候我们可能需要知道 mysql 是如何解析执行我们的 SQL 语句的,比如有时候某些语句写在前面并不一定意味着它就会先执行,有没有使用到索引等待,此时我们可以通过 explain 语句来分析出 SQL 优化器是如何解析执行我们的 SQL 语句的。

使用 EXPLAIN 关键字可以模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理你的 SQL 语句的,explain 主要用于分析查询语句或表结构的性能瓶颈。

 

1.1、explain的作用

通过explain+sql语句可以知道如下内容:

  1. 表的读取顺序(对应id)。
  2. 数据读取操作的操作类型(对应select_type)。
  3. 哪些索引可以使用(对应possible_keys)。
  4. 哪些索引被实际使用(对应key)。
  5. 表直接的引用(对应ref)。
  6. 每张表有多少行被优化器查询(对应rows)。

 

2、explain的基本使用

使用 explain 关键字来分析 SQL 语句的性能,只需要在 SQL 语句的前面加上 explain 即可,语法如下:

explain sql语句;
-- 示例
explain select * from tbl_emp,tbl_dept where tbl_emp.deptId = tbl_dept.id;

执行结果:

 

3、explain的字段意思

使用 expain 分析 SQL 性能时,列出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra。

概要描述:

  • id:表的读取顺序
  • select_type:数据读取操作的操作类型。
  • table:该查询是基于哪张表的
  • partitions:匹配的分区
  • type:表示查询的访问类型
  • possible_keys:哪些索引可以使用
  • key:哪些索引被实际使用
  • key_len:索引字段的长度
  • ref:表直接的引用
  • rows:扫描出的行数(估算的行数)
  • filtered:按表条件过滤的行百分比
  • Extra:执行情况的描述和说明

 

3.1、id(表的读取顺序)

explain 分析出来的 id 字段表示查询中执行 select 子句或操作表的顺序。比如,当查询的 SQL 语句涉及到多个表时,explain 分析出来的数据就有多条,其中 id 值越大的,表示SQL优化器会越早执行这个表。

其中,有三种情况:id全部相同、id全部不同、id部分相同。

 

3.1.1、id全部相同(执行顺序由上至下)

比如我们执行 explain 来分析某条SQL语句,其中涉及到三个表。如下图:

可以看到结果中,id全部都相同,此时意味着 SQL 优化器的执行顺序为由上至下。也就是 SQL 优化器实际上的执行计划是:先执行 t1 表的查询,再执行 t3 表,最后执行 t2 表。

 

3.1.2、id全部不同(id越大,越先被执行)

比如我们执行 explain 来分析某条SQL语句,其中涉及到三个表。如下图:

可以看到结果中,id全部不同,id 值越大优先级越高,越先被执行。也就是 SQL 优化器实际上的执行计划是:先执行 t3 表的查询,再执行 t2 表,最后执行 t1 表。

一般当涉及到子查询时,id 的序号会递增,id 值越大优先级越高,越先被执行.

 

3.1.3、id部分相同(相同id由上至下执行)

比如我们执行 explain 来分析某条SQL语句,其中涉及到三个表。如下图:

可以看到结果中,id部分相同,部分不同,此时仍然适用 id 值越大越先被执行的原则,id 相同的可以认为是同一组,从上往下顺序执行。也就是 SQL 优化器实际上的执行计划是:先执行 t3 表的查询,再执行衍生表 derived2,最后执行 t2 表。

(衍生表 derived2 的意思是该衍生表是 id 为2,即 t3 表的虚拟表)

 

3.2、select_type(查询操作的类型)

select_type 代表查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询。

select_type 的值和含义如下:

  • SIMPLE:简单的 select 查询,查询中不包含子查询或者 UNION。

 

  • PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为 Primary。

 

  • DERIVED:在 FROM 列表中包含的子查询被标记为 DERIVED(衍生) MySQL 会递归执行这些子查询,,把结果放在临时表里。

 

  • SUBQUERY:在SELECT或WHERE列表中包含了子查询。

 

  • DEPEDENT SUBQUERY:在SELECT或WHERE列表中包含了子查询,子查询基于外层。

 都是 where 后面的条件,subquery 是单个值,dependent subquery 是一组值。

 

  • UNCACHEABLE SUBQUERY:无法使用缓存的子查询。

 当使用了@@来引用系统变量的时候,不会使用缓存。

 

  • UNION:若第二个SELECT出现在UNION之后,则被标记为UNION; 若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED。

 

  • UNION RESULT:从UNION表获取结果的SELECT。

 

3.3、TYPE(查询类型)

type 是查询的访问类型,表示该查询使用了哪种查询类型,是较为重要的一个指标。

结果值从最好到最坏依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL。常见的有:system > const > eq_ref > ref > range > index > ALL

一般来说,得保证查询至少达到 range 级别,最好能达到 ref。

 

3.3.1、system 查询类型

当某个表只有一行记录时(等于系统表),查询该表的查询类型会是 system。这是 const 类型的特例,平时很少会出现。

 

3.3.2、const 查询类型

常量查询,表示通过索引Index一次就找到了。用于比较 primary key=常量 和 unique=常量 这种索引。

比如将主键置于 where 查询条件中,MySQL 就能将该查询转换为一个常量,也就是使用常量查询。因为只匹配一行数据,所以该查询类型查询效率很快。

比如下面 t1 表中 id 字段建了索引,执行计划如下:

 

3.3.3、eq_ref 查询类型

唯一性索引扫描,对于每个索引键,表中只对应一行数据,常见于主键或唯一索引扫描。

 

3.3.4、ref 查询类型

非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行, 然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。

示例:

没用索引前:

建立索引后:

 

3.3.5、range 查询类型

只检索给定范围的行,使用一个索引来选择行,key 列显示使用了哪个索引,一般就是在你的 where 语句中出现了 between、<、>、in 等的查询。这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。

 

3.3.6、index 查询类型

全索引扫描(FULL INDEX SCAN),只遍历索引树,通常比ALL快,因为索引文件通常比数据文件小。index 与 ALL 都是全表查询,但 index 是从索引中读取,而 ALL是从全表中读取。

出现 index 是 sql 使用了索引但是没有通过索引进行过滤,一般是使用了覆盖索引或者是利用索引进行了排序分组。

 

3.3.7、all 查询类型

全表扫描(FULL TABLE SCAN),遍历全表找到匹配的行。速度最慢,应避免使用。

 

3.4、possible_keys和key

possible_keys:显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,一个或多个,但不一定被查询实际使用。

key:实际使用的索引。如果为NULL,则表示没有使用到索引。常见的可能原因:1、没有建索引。2、sql语句写法错误,索引失效。3、possible_key也为NULL时,表示用不到索引。

 

3.5、key_len

key_len表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在使用联合索引的时候,判断该索引有多少部分被使用到非常重要。

key_len的长度计算公式很重要。如果是单列索引不用去计算,因为没有意义,如果是组合索引,知道key_len的长度是非常有意义的,key_len越小,说明索引效果越好

key_len 计算公式可参考:https://blog.csdn.net/u012068483/article/details/105270813

 

3.6、ref

显示索引的哪一列被使用了,有可能是一个常数。显示哪些列或常量被用于查找索引列上的值。

 

3.7、rows(行数)

rows 列显示 MySQL 根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。该值越少越好。

 

3.8、Extra

该列用来显示其他的一些额外的重要的信息。

其取值有以下几个:

  • Using filesort(文件排序)

当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”。

Using filesort表明 mysql 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。mysql中无法利用索引完成的排序操作称为“文件排序”。出现Using filesort就非常危险了,在数据量非常大的时候几乎“九死一生”,出现Using filesort需尽快优化sql语句。

示例:

当 deptname字段未建索引时:

为deptname字段创建索引后:

 

  • Using temporary

使用了临时表保存中间结果,常见于排序order by和分组查询group by。出现这种情况非常危险,“十死无生”,急需对SQL进行优化。

示例:

将tb_emp中name的索引先删除,出现如下图结果,非常烂,Using filesort和Using temporary,“十死无生”。

为name字段创建索引后:

 

  • Using index

表明相应的 select 操作中使用了覆盖索引,避免访问表的额外数据行。出现这个提示是好兆头,表明该SQL的效率不错。

如果同时出现了Using where,表明索引被用来执行索引键值的查找。如果没有同时出现Using where,表明索引用来读取数据而非执行查找动作。

 

  • Using where

表明使用了 where 过滤。

 

  • Using  join buffer

使用了连接缓存。该值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进。

 

  • Impossible where

出现这个值说明 where 语句的条件总是 false,无法查询到任何符合条件的行。此时可能需要检查 SQL 语句是否正确。

 

posted @ 2022-01-26 23:35  wenxuehai  阅读(1074)  评论(0编辑  收藏  举报
//右下角添加目录