MySQL EXPLAIN

3 篇文章 1 订阅
EXPLAIN语句用于分析MySQL如何执行SQL查询,包括如何使用索引、扫描的行数等,帮助优化查询性能。通过分析id、select_type、table、type等列,可以判断查询是否有效利用了索引,以及查询效率。优化目标通常是达到range级别或更好的关联类型。
摘要由CSDN通过智能技术生成

工作中时,我们在数据库创建了索引,那我们如何知道我们利用上了索引没有?

EXPLAIN语句提供了MySQL如何执行语句的信息,从而知道MySQL是如何处理你的SQL语句的,可以帮助选择更好的索引和写出更优化的查询语句。EXPLAIN适用于SELECT、DELETE、INSERT、REPLACE和UPDATE语句。

下面是使用 explain 的例子:

mysql> explain select * from test;
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEtestALLNULLNULLNULLNULL2NULL

在旧的MySQL版本中,分区和扩展信息是使用EXPLAIN PARTITIONS和EXPLAIN extended生成的:
1)explain extended:会在 explain 的基础上额外提供一些查询优化的信息。紧随其后通过 show warnings 命令可以 得到优化后的查询语句,从而看出优化器优化了什么。
2)explain partitions:相比 explain 多了个 partitions 字段,如果查询是基于分区表的话,会显示查询将访问的分区。
这些语法仍然可以用于向后兼容性,但是分区和扩展输出在新版本默认启用,因此PARTITIONS和extended关键字是多余的,不建议使用。

explain 中的列

字段含义
id该语句的唯一标识
select_type查询类型
table表名
partitions匹配的分区
type联接类型
possible_keys可能的索引选择
key实际选择的素引
key_len索引的长度
ref索引的哪一列被引用了
rows估计要扫描的行
filtered表示符合查询条件的数据百分比
Extra附加信息

接下来我们将解读 explain 中每个列的信息:

1.id列

这是查询中SELECT的序号,如果是其他行并集结果,则为NULL。如果explain的结果包括多个不同的id值,则数字越大越先执行;而对于相同id的行,则表示从上往下依次执行。

2.select_type列
查词类型作用
SIMPLE简单查询(未使用UNION或子查询)
PRIMARY复杂查询中最外层的查询
UNION在UNION中的第二个和随后的SELECT被标记为UNION。如果UNION被FROM子句中的子查询包含,那么它的第一个SELECT会被标记为 DERIVED
DEPENDENT UNIONUNION中的第二个或后面的查询,依赖了外面的查询
UNION RESULTUNION的结果
SUBQUERY子查询中的第一个SELECT(不在 from 子句中)
DEPENDENT SUBQUERY子查询中的第一个SELECT,依赖了外面的查询
DERIVED用来表示包含在FROM子句的子查询中的SELECT, MySQL会递归执行并将结果放到一个临时表中。MySQL内部将其称为是Derived table(派生表),因为该临时表是从子查询派生出来的
DEPENDENT DERIVED派生表,依赖了其他的表
MATERIALIZED物化子查询
UNCACHEABLE SUBQUERY子查询,结果无法缓存,必须针对外部查询的每一行重新评估
UNCACHEABLE UNION属于UNCACHEABLE SUBQUERY的第二个或后面的查询

例子:

mysql> explain select * from film where id = 2;
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEfilmconstPRIMARYPRIMARY4const1NULL
mysql> explain select 1 union all select 1;

在这里插入图片描述

mysql> explain select (select 1 from t_jxkh_xnyx where id = 1) from (select * from t_jxkh_pici where id = 1) pc;

在这里插入图片描述

3.table列

表示当前这一行正在访问哪张表,如果SQL定义了别名,则展示表的别名。
当 from 子句中有子查询时,table列是格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。可以是以下值之一 :
<unionM,N>:表示id值为M和N的行并集。
< derivedN>:该行指向id值为n的行的派生表结果。例如,派生表可能来自from子句中的子查询。
< subqueryN>:该行指向id值为n的行的物化子查询结果。

4.partitions

当前查询匹配记录的分区。对于未分区的表,返回NULL

5.type

这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行。
依次从最优到最差分别为:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,好的sql查询至少达到range级别,最好能达到ref。

NULL:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表。

mysql> explain select min(id) from t1;

在这里插入图片描述

system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,可以忽略不计。

const:表示通过索引一次就找到了,const用于primary key 或者 unique索引的等值查询。因为只需匹配一行数据,所有很快。如果将主键置于where列表中,mysql就能将该查询转换为一个const。

mysql> explain select * from t1 where id=1;

在这里插入图片描述

eq_ref:primary key 或 unique not null 索引的所有部分被连接使用,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type。

explain select * from t_jxkh_khcjzf a left join t_jxkh_pici b on a.pici_fk = b.id;

在这里插入图片描述

ref:当满足索引的最左前缀规则,或者索引不是主键也不是唯一索引时才会发生。如果使用的索引只会匹配到少量的行,性能也是不错的。

explain select * from t_jxkh_khcjzf where gh='gh';

在这里插入图片描述

fulltext:全文索引。

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

SELECT * FROM t_jxkh_khcjzf WHERE gh='gh' OR gh IS NULL;

在这里插入图片描述

index_merge:此类型表示使用了索引合并优化,表示一个查询里面用到了多个索引。

explain select * from t_jxkh_khcjzf where gh='1111' or id=2;

在这里插入图片描述

unique_subquery:该类型和eq_ref类似,但是使用了IN查询,且子查询是主键或者唯一索引。

index_subquery:和unique_subquery类似,只是子查询使用的是非唯一索引。

range:范围扫描,表示检索了指定范围的行,主要用于有限制的索引扫描。比较常见的范围扫描有>、>=、<、<=、IS NULL、<=>、BETWEEN、LIKE、IN()等操作符。这种索引列上的范围扫描比全索引扫描要好。只需要开始于某个点,结束于另一个点,不用扫描全部索引。

explain select * from t_jxkh_khcjzf where id>1

在这里插入图片描述

index:Full Index Scan全索引扫描,和ALL类似,只不过index是全盘扫描了索引的数据。当查询仅使用索引中的一部分列时,可使用此类型。有两种场景会触发:
如果索引是查询的覆盖索引,并且索引查询的数据就可以满足查询中所需的所有数据,则只扫描索引树。此时,explain的Extra 列的结果是Using index。index通常比ALL快,因为索引的大小通常小于表数据。
按索引的顺序来查找数据行,执行了全表扫描。此时,explain的Extra列的结果不会出现Uses index。

explain select id from t_jxkh_khcjzf

在这里插入图片描述

ALL:Full Table Scan全表扫描,性能最差。

6.possible_keys

这一列显示查询可能使用哪些索引来查找,但不一定被查询实际使用。如果此列为NULL,则没有相关索引。在这种情况下,您可以通过检查WHERE子句来检查它是否引用了一些适合建立索引的列,如果是,创建适当的索引,从而提高查询的性能。

7.key

这一列显示mysql实际使用索引。
如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force index、ignore index。

8.key_len

这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。如果key列显示NULL, key_len列也显示NULL。由于存储格式,当字段允许为NULL时,key_len比不允许为空时大1字节。

key_len计算规则如下:

字符串
char(n):n字节长度,如果是utf-8,则长度 3n
varchar(n):多2字节存储字符串长度,如果是utf-8,则长度 3n + 2
数值类型
tinyint:1字节
smallint:2字节
int:4字节
bigint:8字节  
时间类型 
date:3字节
timestamp:4字节
datetime:8字节
如果字段允许为 NULL,需要1字节记录是否为 NULL。

varchr(n)变长字段且允许NULL=n*(character set: utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)
varchr(n)变长字段且不允许NULL =n*(character set: utf8=3,gbk=2,latin1=1)+2(变长字段)
char(n)固定字段且允许NULL=n*(character set: utf8=3,gbk=2,latin1=1)+1(NULL)
char(n)固定字段且不允许NULL=n*(character set: utf8=3,gbk=2,latin1=1)

索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。

9.ref

这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),func,NULL,字段名。
如果ref是一个函数,则使用的值是函数的结果。要想查看是哪个函数,可在EXPLAIN语句之后紧跟一个SHOW WARNINGS语句。

10.rows

MySQL估算会扫描的行数,注意这个不是结果集里的行数,数值越小越好。对于InnoDB表,这个数字是一个估计值,可能并不总是准确的。

11.filtered

表示符合查询条件的数据百分比,最大值为100,这意味着没有发生行过滤,从100开始递减的值表示过滤量的增加。用rows × filtered可获得和下一张表连接的行数。例如rows = 1000,filtered = 50%,则和下一张表连接的行数是500。

在MySQL 5.7之前,想要显示此字段需使用explain extended命令;
MySQL.5.7及更高版本,explain默认就会展示filtered。

12.Extra

展示有关本次查询的附加信息。常见的重要值如下:
distinct:一旦mysql找到了与行相联合匹配的行,就不再搜索了。

select DISTINCT a.gh from t_jxkh_xnyx a left join t_jxkh_khcjzf b on a.gh=b.gh

在这里插入图片描述

Using index:这发生在对表的请求列都是同一索引的部分的时候,返回的列数据只使用了索引中的信息,而没有再去访问表中的行记录。是性能高的表现。同上个例子,gh是索引列。
在这里插入图片描述

Using where:mysql服务器将在存储引擎检索行后再进行过滤。就是先读取整行数据,再按 where 条件进行检查,符合就留下,不符合就丢弃。

explain select * from t_jxkh_khcjzf where id > 1

在这里插入图片描述

Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。

select DISTINCT gh from t_jxkh_xnyx

在这里插入图片描述

select DISTINCT gh from t_jxkh_khcjzf

在这里插入图片描述

Using filesort:mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据联接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的。

select gh from t_jxkh_xnyx order by gh

在这里插入图片描述

select gh from t_jxkh_khcjzf order by gh

在这里插入图片描述

Impossible WHERE:WHERE子句始终为false,不会命中任何行。

select gh from t_jxkh_khcjzf WHERE 1=2

在这里插入图片描述

Impossible HAVING:HAVING子句始终为false,不会命中任何行。
No tables used:当此查询没有FROM子句或拥有FROM DUAL子句时出现。例如:

explain select 1

在这里插入图片描述

Not exists:MySQL能对LEFT JOIN优化,在找到符合LEFT JOIN的行后,不会为上一行组合中检查此表中的更多行。例如:

SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;

在这里插入图片描述

参考:https://zhuanlan.zhihu.com/p/281517471
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值