保姆级的MySQL执行计划(Explain)解读

什么是执行计划

在查询语句开头添加explain关键字,然后执行查询,就可以看到执行计划。执行计划代表这个SQL执行的过程,MySQL解释器将如何处理该SQL,通过对执行计划的分析,方便做SQL优化。

数据准备

当前数据库版本为8.0.42

用到的表信息如下:

查询计划解读

下面针对执行计划的每个字段进行举例和说明:

id

id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。

id=1的表是驱动表。

select_type

select_type 查询类型,说明查询的种类,有以下几种:

1.simple 简单查询。查询不包含子查询和union

2.primary:复杂查询中最外层的 select

3.derived:包含在 from 子句中的子查询。MySQL会将结果存放在一个临时表中,也称为派生表(derived的英文含义)

4.union:在 union 中的第二个和随后的 select

5.union result:从 union 临时表检索结果的 select

6.subquery:包含在 select 中的子查询(不在 from 子句中)

table

这一列表示 explain 的一行正在访问哪个表。

如果有具体表名,则表示读取这个表。例如film,表示对film表进行读取。

如果没有具体表名,则表示对id为对应编号的记录进行操作。例如<union3,4>,表示将id为3和4的两条记录进行union的联合查询。

partitions

说明查询作用在哪个分区表上,如果没有对表进行分区,则为null。

type

这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行。

type的类型有12种,下面举例说明,越靠前的类型是效率越高的类型,也就是说在SQL优化时,尽可能使用下面列出的前面的类型。

标记*号的为常用的类型。

1.system

查询的表只有 0 或 1 行(表的数据库引擎必须是 MyISAM或MEMORY,InnoDB 不行),system效率最高。

2.const *

mysql能对查询的某部分进行优化并将其转化成一个常量。

用于 primary key 或 unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取1次,速度比较快。

3.eq_ref *

primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。

这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type。

直白点说就是一张表的主键字段和另一张表的外键进行关联,就是eq_ref类型。

4.ref *

相比eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。

5.fulltext

全文索引,使用极少。

6.ref_or_null *

类似ref,但是可以搜索值为NULL的行。

当检索的数据包含null时,对应类型为ref_or_null。

7.index_merge

使用极少。

8.unique_subquery

使用极少。

9.index_subquery

使用极少。

10.range *

范围扫描,通常出现在 in(), between ,> ,<, >= 等操作中。

使用一个索引来检索给定范围的行。

range的执行效率不确定,会根据不同的查询条件或高或低。比如ID>1,效率就低,因为要在很多条数据中检索。如果换成ID<10,效率就比较高,因为只需要扫描前面9条记录。

11.index *

基于索引进行全表扫描,和ALL差不多,不同点就是mysql只需扫描索引树,这通常比ALL快一些。

12.ALL *

即全表扫描,意味着mysql需要从头到尾去查找所需要的行。

通常情况下这需要增加索引来进行优化了。

possible_keys

这一列显示查询可能使用哪些索引来查找。

key

key列显示mysql实际采用哪个索引来优化对该表的访问。

key_len

这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。

这里显示4,是因为主键ID为int类型,占用4字节。

ref

这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:

const(常量),func,NULL,字段名(例:film.id

row

这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。

filtered

是一个百分比的值,代表 (rows * filtered) / 100 ,这个结果将于前表产生交互。

当建立了索引的情况,一般为100,或者是接近100的比较大的一个值。

Extra

这一列展示的是额外信息。有以下一些类型:

distinct

一旦mysql找到了与行相联合匹配的行,就不再搜索了。

Using index

这发生在对表的请求列都是同一索引的部分的时候,返回的列数据只使用了索引中的信息,而没有再去访问表中的行记录。是性能高的表现。

using index也叫索引覆盖,只通过索引字段就可以完成查询。

Using where

mysql服务器将在存储引擎检索行后再进行过滤。

就是先读取整行数据,再按 where 条件进行检查,符合就留下,不符合就丢弃。

代表数据访问效率不高。

using temporary

mysql需要创建一张临时表来处理查询。

出现这种情况一般是要进行优化的,首先是想到用索引来优化。

下面创建一个索引

再次进行查询

添加索引后,查询就不再创建临时表,而是用索引覆盖,提升了效率。

using filesort

采用文件扫描对结果进行计算排序,效率很差。

这里可能会产生疑惑,已经在name字段上创建了索引,为什么排序还是文件排序,没有用到索引呢,这是因为对于排序,只有select 字段 与order by 字段都被索引覆盖是才允许使用Using Index。把查询语句中的*改成name,再看下效果:

这样就用到了索引。

下面再看一种情况,如果要查询多个字段,排序也是多个字段,会是什么情况呢?

同时用name ,update_time两个字段进行查询和排序,又变成了文件排序。

这是因为只有name字段有索引,而update_time字段没有。

下面为name ,update_time建立复合索引。

然后再查询

这次就用到了索引。

注意order by后面的字段顺序,需要与索引字段顺序一致,否则会导致索引失效。

相关推荐
小魏每天都学习3 分钟前
【数据库-范式-ER图-SQL结合】
数据库
阿坤带你走近大数据5 分钟前
Oracle存储过程与触发器的详细介绍
数据库·oracle
2401_8633186311 分钟前
基于RS-232C的串口通信
数据库·mongodb
csdn_aspnet21 分钟前
用 MySQL 玩转数据可视化:从底层数据到 BI 工具的桥接
数据库·mysql·信息可视化·bi
明洞日记26 分钟前
【软考每日一练013】解析嵌入式网络数据库(NDB)架构
数据库·5g·嵌入式·软考·嵌入式实时数据库
wb0430720127 分钟前
一次jvm配置问题导致的数据库连接异常
服务器·jvm·数据库·后端
酷酷的崽79827 分钟前
搭载cpolar,让PostgreSQL数据库远程访问超丝滑
数据库·postgresql
API开发34 分钟前
apiSQL 迁移至已有 PostgreSQL 数据库指南
数据库·postgresql·api开发·postgrest·接口开发工具·api管理软件
学掌门37 分钟前
从数据库到可视化性能,5个大数据分析工具测评,python只排倒数
数据库·python·数据分析
编程小风筝38 分钟前
Django REST framework实现安全鉴权机制
数据库·安全·django