The
EXPLAIN
statement provides information about how MySQL executes statements.
简单翻译下就是 EXPLAIN 提供 MySQL 如何执行语句的信息,我们举个例子
EXPLAIN SELECT name FROM app_user WHERE id = 1;
就是在你要执行的查询语句前加一个EXPLAIN
,就可以查看执行当前语句的具体信息,比如属于什么查询类型啦~走了什么索引啦(具体如下图)~
总的来说,通过EXPLAIN
我们可以获取以下信息:
- 表的读取顺序
- 数据读取操作的操作类型
- 使用了哪些索引
- 每张表优化器查询了多少行数据
编辑
我们在碰到一些类型“慢查询”问题时,一般会使用EXPLAIN
来分析我们的SQL还有哪些地方可以做优化,具体就是根据上图中列表字段进行分析的,本篇就把EXPLAIN
的关键字段挖个地儿朝天,👩再也不用担心要如何对SQL进行优化叻( ̄∇ ̄)/
ID
ID越大越先执行,一致按先后顺序执行
select_type 查询类型
这里只列出了常见的几种,想更加深入可以戳官网
dev.mysql.com/doc/refman/…https://dev.mysql.com/doc/refman/8.0/en/explain-output.html#explain_select_type
SIMPLE
简单查询(无联合查询或者子查询)PRIMARY
复杂查询中最外层的selectDERIVED
from后面的临时表(派生表)SUBQUERY
select后面的临时表UNION
union中第二个(或者说后一个)select
table 表名
表示结果集出自哪张表
举个🌰,如果某个查询table的值为<devired3>
的含义就是这个select是从ID为3的派生表中进行查询的
type 关联类型/访问类型
类型 | 解释 | 备注 |
NULL | 在优化阶段分解查询语句,使得在执行阶段无需再访问表/索引 | |
system | 无需进行磁盘IO,并且要查询的结果集只有一行记录 | 属于constant 的特殊情况 |
constant | 查找主键索引,MySQL能对查询的某部分进行优化将其转换为一个常量(走主键(primary key)或者唯一(unique key)索引),所以表中最多有一个匹配行,只需要读取1次 | - 可以使用show warnings; 查看优化后的版本 |
eq_ref | 查找唯一性索引,比如表链接时,使用主键/唯一索引进行关联的表查询,最多只会返回1条数据 | |
ref | 使用普通索引/非唯一性索引(从根节点开始),或者唯一性索引的部分前缀,索引要进行比较,有可能查出多条结果集 | 使用了联合主键前缀也是这种类型 |
range | 查询某个索引的部分索引,范围扫描,通常出现在in() /between /> /< />= /<= 等操作中,使用一个索引来检索指定范围 |
查询效率跟结果集大小相关(可使用分页等方式进行优化) |
index (全索引扫描) | 查找全部索引树,表示扫描全索引可以拿到结果(从1开始遍历),一半是扫描某个二级索引,这种扫描一般不会从索引树根节点开始快速查找,而是直接对二级索引的叶子节点遍历和扫描,速度还是比较慢的,这种查询一般会使用覆盖索引,二级索引一般比较小(主键索引包含数据,一般会比较大,因而读取的磁盘数据较大),所以index通常会比ALL快一些 | 如果主键索引和二级索引都包含结果集,MySQL会选用小的索引进行查询。虽然index也使用到了索引,但是和ref使用索引的方式不同,index是通过叶子节点从第一条索引开始向下遍历的,而ref是从索引的根节点开始折半查找,因而ref效率比index快很多ALL全表扫描,不使用任何索引,从第一个主键(聚簇索引的所有叶子节点)开始向下查找 |
possible_keys
MySQL觉得可能要用到的索引
key
实际用到的索引
key_len
用到的索引的长度(比如可用于判断使用了联合索引中的哪几个)
类型 | 具体类型 | 长度 | |
字符串 | char(n) | n字节 | |
varchar(n) | 如果是utf-8则长度3n+2 字节,加的2字节用于存储字符串长度 |
utf-8一个占3字节 | |
数值类型 | tinyint | 1字节 | |
smallyint | 2字节 | ||
int | 4字节 | ||
bigint | 8字节 | ||
时间类型 | date | 3字节 | |
timestamp | 4字节 | ||
NULL | NULL | 1字节 | 允许为空还有1个字段记录是否为空 |
一般来讲,索引的最大长度是768字节,当字符串过长时,MySQL会做一个类似左前缀索引的处理,将前半部分的字符串提取出来做索引
ref
表查找值所用的列(表名.字段)或常量(const)
这一列显示了在key列记录的索引中,表查找值所用到的列/常量
row
预估要读取并检测的行数
Extra
额外信息
- Using index
查询结果集使用了覆盖索引(覆盖索引是一种查询方式,表示要查询的结果字段在查询的索引树中全部包括,无需再回表)
覆盖索引是指MySQL执行计划explain结果里的key有使用索引,如果select后面查询的字段都可以从这个索引树中获取,这种情况一般可以说是使用了覆盖索引,extra列中就会显示Using Index;覆盖索引一般针对的是辅助索引,整个查询结果只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其他字段值
优化点
如果出现回表的情况,即在查询字段中有一个字段没有加索引或者出现索引失效的问题,导致sql回表走了全表扫描,就可以使用覆盖索引进行优化
-
Using index condition
查询的列不完全被索引覆盖,where条件之前一个前导列的范围
-
Using temporary/Using filesort
使用了临时表
-
Using where
使用Where语句处理结果,并且查询到的列未被索引覆盖
……
上面是一些常见的类型,其他还有很多,感兴趣可以参考官网
MySQL :: MySQL 8.0 Reference Manual :: 8.8.2 EXPLAIN Output Format