MySql 之 explain 执行语句分析
前置:建表语句
CREATE TABLE `test_user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
`user_id` varchar(36) NOT NULL COMMENT '用户id',
`user_name` varchar(30) NOT NULL COMMENT '用户名称',
`phone` varchar(20) NOT NULL COMMENT '手机号码',
`lan_id` int NOT NULL COMMENT '本地网',
`region_id` int NOT NULL COMMENT '区域',
`create_time` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `un_idx_phone` (`phone`) USING BTREE,
KEY `idx_user_id` (`user_id`),
KEY `idx_uid_phone` (`user_id`,`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1010001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
1.explain 用法
explain + sql语句
2.描述符含义
描述符 | 含义 |
---|---|
id | 执行顺序。(id 越大越先执行、id 相同由上至下) |
select_type | 查询的类型 |
table | 显示这一行的数据是关于哪张表的 |
partitions | 使用的哪个分区,需要结合表分区才可以看到 |
type | type显示的是访问类型,是较为重要的一个指标 |
possible_keys | 查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用 |
key | 实际使用的索引。如果为NULL,则没有使用索引 |
key_len | 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度;key_len应尽量短,越短效率越高 |
ref | 哪些列或常量被用于查找索引列上的值 |
rows | 显示MySQL认为它执行查询时必须检查的行数,越小越好 |
filtered | 表示返回结果的行数占需读取行数的百分比,越大越好 |
Extra | 一些额外信息 |
2.1 id 介绍
2.1.1 id 相同
id 相同,是同一组,执行顺序由上至下
2.1.2 id 不同
id 不同,不是同一组,执行顺序按 id 由大到小
注意:这条语句 tu.id = 不能改成 tu.id in,我使用 mysql 是8.* 版本,in (sql语句) 会被优化城 join 语句,所有看到的是这样的
2.2 select_type 介绍
select_type 类型 | 解释 | 示例 |
---|---|---|
SIMPLE | 简单SELECT,不使用UNION或子查询等 | ![]() |
PRIMARY | 子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY | ![]() |
UNION | UNION中的第二个或后面的SELECT语句 | ![]() |
DEPENDENT UNION | UNION中的第二个或后面的SELECT语句,取决于外面的查询 | |
UNION RESULT | UNION的结果,union语句中第二个select开始后面所有select | |
SUBQUERY | 子查询中的第一个SELECT,结果不依赖于外部查询 | |
DEPENDENT SUBQUERY | 子查询中的第一个SELECT,依赖于外部查询 | |
DERIVED | 派生表的SELECT, FROM子句的子查询 | |
UNCACHEABLE SUBQUERY | 一个子查询的结果不能被缓存,必须重新评估外链接的第一行 |
2.3 table 介绍
显示这一步所访问数据库中表名称(显示这一行的数据是关于哪张表的),有时不是真实的表名字,可能是简称
2.4 partitions 介绍
暂无
2.5 type 介绍
对表访问方式,表示MySQL在表中找到所需行的方式,又称“访问类型”。
类型 | 说明 | 性能从低到高 | 示例 |
---|---|---|---|
ALL | Full Table Scan, MySQL将遍历全表以找到匹配的行 | 1 | ![]() |
index | Full Index Scan,index与ALL区别为index类型只遍历索引树 | 2 | ![]() |
range | 只检索给定范围的行,使用一个索引来完成 | 3 | ![]() |
ref | 使用非唯一性索引检索,返回匹配某个单独值的所有行 | 4 | ![]() |
eq_ref | 唯一性索引检索,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描 | 5 | |
const | 表示通过索引一次就找到了,const用于比较primary key或者unique索引,如将主键置于where列表中,MySQL就能将该查询转换为一个常量 | 6 | ![]() |
system | 表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计 | 7 | |
NULL | 8 |
2.6 possible_keys 介绍
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用
2.7 key 介绍
实际使用的索引。如果为NULL,则没有使用索引
2.8 key_len 介绍
表示索引中索引键使用的字节数,可通过该列计算查询中使用的索引的长度
key_len应尽量短,越短效率越高
2.9 ref 介绍
哪些列或常量被用于查找索引列上的值。如果是列,则显示字段名;如果是常数,则显示const
常量被用于查找索引树上的值,那么 ref = const
列被用于查找索引树上的值,那么 ref = 列
2.10 rows 介绍
显示MySQL认为它执行查询时必须检查的行数,越小越好
注意,针对limit语句,这个是不准确的
这里真实 rows = 100
2.11 filtered 介绍
表示返回结果的行数占需读取行数的百分比,越大也就意味着有效查询越高
2.12 Extra 介绍
一些额外信息
类型 | 说明 | 示例 |
---|---|---|
Using filesort | 无法利用索引完成的排序操作称为“文件排序” | ![]() |
Using temporary | 使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于分组查询group by | ![]() |
Using index | 索引覆盖 | ![]() |
Using where | 触发条件 = 需要回表 + where过滤 | ![]() |
Using where & Using index | 触发条件=不能回表 + 使用了二级索引 + where过滤 | ![]() |
Using index condition | 索引下推 ,触发条件 = 需要回表 + 使用了二级索引 + where条件可以放在innodb层过滤 | ![]() |
Using join buffer | 使用了连接缓存 |
疑惑?
explain select id from test_user where user_id < '4d91881a-b157-11ec-9699-7c10c99db896';
该执行计划 Extra 字段为啥是 Using where & Using index?个人理解是 service 层还要进行一遍 user_id > 过滤,可能各种引擎(mysiam)没有很好的实现(a > 0、a >= 0)这种检索,会把 0 也带出来,所以需要 service 层进一步过滤