数据库(6)Mysql中explain分析SQL语句执行效率

这一段时间一直在学习关系型数据库,准备写一个小专题来总结一下这一段时间的学习结果。

写下这篇博文之前,我学习了大量的关于数据库索引的基础知识,所以如果想更好的理解explain的用法,请先耐心学习 ——数据库索引

一. 什么是explain?

explain是Mysql的一个关键字,用来分析某条SQL语句执行过程和执行效率。

explain又叫执行计划,主要是用来查看优化器将决定如何执行查询过程,比如究竟是全表扫描还是索查询,还可以看到那种访问策略是优化器使用的,比如究竟是直接访问索引内容,还是又进行了筛选过滤,亦或者回查聚合索引等等/

我们先看看一下,通过explain关键字可以获得什么信息:

这里写图片描述

可以看到信息有如上图几点:

  1. id:执行编号,表示SELECT所属的行。如果SQL语句中没有子查询或者关联查询,那么id只有唯一的1,如果有子查询和关联查询,那么就会有多个id。
  2. select_type:标志本行是简单查询还是其他复杂查询
  3. table:标识本行查询是访问了哪个表
  4. type:标识本行查询优化器会使用什么方式进行查询,这个很重要,是我们进行分析的重点内容。
  5. possible_key:标识本行查询可以使用到的全部索引
  6. key:标识本次查询真实使用的索引,这个也很重要
  7. key_len:标识本次查询使用索引的长度,单位是字节数
  8. ref:标识使用索引查询时,使用了那种数据值进行选择,可以是常量,也可以是其余表的字段值
  9. row:显示本次查询会有多少行结果被影响
  10. Extra:一些额外信息,但也很重要

二 . 关键字分析:

2.1 id

这里写图片描述

可以看到有多子句查询的时候,id会有多个,执行顺序是从大到小,也就是说id为2的子句先执行,然后是id为1的语句执行。

这里写图片描述
而对于连接查询,虽然有两次查询过程,但是id都是1,因为他们是并列关系不是嵌套关系,id相等的情况下执行顺序自上至下。

2.2 select_type

常见的分为如下几种:

  1. SIMPLE:简单查询,不包括子句和联合查询(union
  2. PRIMARY:包含子查询或者联合查询,最外层标识为PRIMARY
  3. SUBQUERY:这个很容易理解了,就是子查询内层的子句,被标识为SUBQUERY
  4. DERIVED:派生表,子查询中派生出来的临时表,位于FROM的子查询中
  5. UNION:位于UNION中联合查询关键字后面的子句,被标记为UNION,但是如果在FROM中还是标识为DERIVED

其余都不会很常见,而且只要弄清楚意思就可以了,因为我们直接看SQL语句也是能看出来各个结构,因此这项并不是很重要。

2.3 table

这个就是显示从哪个表进行了本行查询。

这里写图片描述

还是看这张图,很清晰的显示了两次查询的是哪个表内容。

2.4 type(重点理解)

我们在这里建立了一个test表:
这里写图片描述

表示MySQL在表中找到所需行的方式,又称“访问类型”,常见类型如下:

 ALL, index,  range, ref, eq_ref, const, system, NULL

从左到右,查询性能从最差到最好。至于什么时候会出现这些情况以及为什么出现这些情况,我们看逐一进行分析。

2.4.1 ALL:

全表扫描,不使用索引,在硬盘上一条一条的进行扫描。

这里写图片描述

可以看出,没有WERHE查询子句的情况下会使用全表扫描。同时如果WHERE子句中查询了没有建立索引的字段,也会进行全表查询。
这里写图片描述

这很容易理解,因为wu这个字段没有在任何索引中,所以要mysql安照它进行查询,那么msyql必须要一条一条的遍历表中的行,然后找出符合条件的行进行查询。

2.4.2 index:

index代表使用索引查询,但是遍历整个索引,和全表遍历的差别差不多,只不过读取的数据更少,效率稍微高一些。
这里写图片描述
我们查询建立索引的字段san,可以看到使用了index_1作为索引,但是进行的是全索引的遍历。

2.4.3 range:

range代表使用了B-TREE索引进行了范围查询,利用了B-TREE的查询性质,查询效率比起前两种有了很大的提升。
这里写图片描述
显而易见的索引范围扫描是带有between或者where子句里带有LIKE,<, >查询。当mysql使用索引去查找一系列值时,例如IN()和OR列表,也会显示range(范围扫描),当然性能上面是有差异的。

2.4.4 ref 和 eq_ref:

使用非唯一索引进行查询某个值时是ref,很显然ref也是使用了索引查找的,而且看后面ref字段的值是const,其实和const区别不大。
这里写图片描述

这种查询的效率高于range,因为首先它同样使用了B-TREE索引的性质查询,其次就是它返回的数据较少。

eq_refref效率差不多,只不过eq_ref是在使用唯一索引进行查询时使用到,因此最多返回一条数据。

简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

2.4.5 const 和 system:

使用常量进行索引查询。system是const类型的特例,当查询的表只有一行的情况下,使用system

这里写图片描述

我个人认为这种查询效率,和ref的值为const的查询应该相差无几。

2.4.6 NULL

MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

一些有趣的现象

在之前索引的学习中,我们就知道聚合索引的值会存储在非聚合索引中,下面我们验证一下。

这里写图片描述

id是表的主键,也就是Mysql默认的聚合索引的字段,首先对于index_1,其中的字段只有san,但是我们发现如果查询id字段,这次查询还是直接Using index(索引覆盖),索引覆盖的意思就是索引中包含你想查询的字段,这就证实了非聚合索引(index_1)中确实包含聚合索引(主键索引)的字段id

还有就是最左前缀原则这个我提到过无数次的东西。

这里写图片描述

很明显的说明了,符合最左前缀原则的查询,就可以直接使用建立的组合索引index_2(san,si)进行利用B-TREE索引的 查询

这里写图片描述

这个emmm,自行体会不符合最左前缀原则的查询,使用了index_2进行了全索引扫描,然后再一步进行WHERE条件筛选。

2.5 possible_keys,key

这个上面已经说的很清楚了,possible_keys是可以使用的索引,而key是实际要使用的索引。

这里写图片描述

上图看到,这次查询可以使用index_1(san),或者index_2(san,si),但mysql优化器最终选择了index_1(san),因为更高效开销更小。

2.6 ref ,rows

上面也说的很清楚了,不再这多说。

2.7 Extra(重点了解)

这里我说几种比较常见的:

a. Using index
该值表示相应的select操作中使用了覆盖索引(Covering Index)
上面我也体到这个概念了,这个很容易理解就是直接从索引中就获得了想要的东西,没有必要进行二次查询。
这里写图片描述
可以看出,这次查询就是索引覆盖索引的一次查询,因为id 是聚合索引的值,存在非聚集索引idnex_1中。
这里写图片描述

因为wu字段没有在索引覆盖中,所以需要二次查询。

b. Using where
这个有很多网上博客说的都不太清楚,其实很容易理解,Using where是指通过数据库引擎第一次查询以后,得到一个结果集,但是这个结果集不满足WHERE语句的限制,所以会Mysql会对这个结果集进行一次筛选,最后得到符合限制的数据集。

这里写图片描述

可以根据这句SQL语句进行理解,因为san,si是索引index_2的内容,所以index_2是覆盖索引(Using index)很容易理解,但是查询条件是si='y'这时Mysql采取的手段是,遍历全索引(type:index),然后根据si='y'这个WHERE语句中的条件进行一次筛选。这就是Using where的含义

c. Using temporary
用临时表保存中间结果,常用于GROUP BY 和 ORDER BY操作中,一般看到它说明查询需要优化了,就算避免不了临时表的使用也要尽量避免硬盘临时表的使用。

d. Using index condition
这个意思是mysql会根据索引查找到的内容,作为条件进行下一次的查询操作,可以是排序查询等等操作。
这里写图片描述

根据索引的内容,进行了顺序展示操作,因为id是局聚集索引,存储顺序就是索引顺序,因此不需要排序。

e. Using filesort

MySQL有两种方式可以生成有序的结果,通过排序操作或者使用索引,当Extra中出现了Using filesort 说明MySQL使用了后者,但注意虽然叫filesort但并不是说明就是用了文件来进行排序,只要可能排序都是在内存里完成的。

猜你喜欢

转载自blog.csdn.net/cringkong/article/details/80903858