MySQL Explain 之 type 详解

2021/11/02 16:46
阅读数 195

EXPLAIN 是什么
MySQL 提供了一个 EXPLAIN 命令,它可以对 SQL 语句进行分析,并输出 SQL 执行的详细信息,以供开发人员针对性优化.

例如分析一条 SELECT 语句

EXPLAIN SELECT * FROM `user` WHERE id = 1 


EXPLAIN 结果中的 type 字段
Tips:常见的扫描方式

system:系统表,少量数据,往往不需要进行磁盘 IO
const:常量连接
eq_ref:主键索引 (primary key) 或者非空唯一索引 (unique not null) 等值扫描
ref:非主键非唯一索引等值扫描
range:范围扫描
index:索引树扫描
ALL:全表扫描 (full table scan)
type 扫描方式由快到慢
system > const > eq_ref > ref > range > index > ALL
1.system


上例中,从系统库 mysql 的系统标 proxies_priv 里查询数据,这里的数据在 Mysql 服务启动时候已经加载在内存中,不需要进行磁盘 IO。

官方文档中的解释:该表只有一行(=系统表)。这是const联接类型的特例

2.const
模拟数据
create table user (
  id int primary key,
  name varchar(20)
)engine=innodb;

insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');
Explain 分析结果


上例中 id 是主键 (primary key),连接部分是常量 1,通过索引一次就能找到,速度非常快

场景:

命中主键(primary key) 或者唯一索引(unique)
被连接的部分是一个常量值(const)
3.eq_ref
模拟数据
create table user (
  id int primary key,
  name varchar(20)
)engine=innodb;

insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');

create table user_balance (
  uid int primary key,
  balance int
)engine=innodb;

insert into user_balance values(1,100);
insert into user_balance values(2,200);
insert into user_balance values(3,300);
insert into user_balance values(4,400);
insert into user_balance values(5,500);
Explain 分析结果
ar414


上例中对于前表 user 表中的每一行(row),对应后 user_balance 表只有一行被扫描,这类扫描的速度也非常的快

场景:

联表 (join) 查询
命中主键 (primary key) 或者非空唯一索引 (unique not null)
等值连接
4.ref
模拟数据
同 eq_ref 模拟数据区别:user_balance 表中的主键索引改为普通索引

create table user (
  id int primary key,
  name varchar(20)
)engine=innodb;

insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');

create table user_balance (
  uid int,
  balance int,
  index(uid)
)engine=innodb;

insert into user_balance values(1,100);
insert into user_balance values(2,200);
insert into user_balance values(3,300);
insert into user_balance values(4,400);
insert into user_balance values(5,500);
Explain 分析结果
联表查询

由于后表使用了普通非唯一索引,对于前表 user 表的每一行 (row),后表 user_balance 表可能有多于一行的数据被扫描

单表查询

当 id 改为普通非唯一索引后,常量的连接查询,也由 const 降级为了 ref,因为非唯一索引所以有多于一行的数据被可能被扫描

ref 每一次匹配可能有多行数据返回,虽然它比 eq_ref 要慢,但它仍然是一个很快的 join 类型

场景:

联表查询
普通非唯一索引
5.range
模拟数据
create table user (
  id int primary key,
  name varchar(20)
)engine=innodb;

insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');
insert into user values(5,'zhaoliu');
Explain 分析结果
between

in

>,>=,<,<=

range 比较好理解,它是索引上的范围查询,它会在索引上扫码特定范围内的值

6.index
话外音:当前测试表为 InnoDb,MyISAM 内置了一个计数器,count () 时它直接从计数器中读

index 类型,需要扫描索引上的全部数据,它仅比全表扫描快一点

7.ALL
模拟数据
create table user (
  id int,
  name varchar(20)
)engine=innodb;

insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');
insert into user values(5,'zhaoliu');
Explain 分析结果


如果 id 上不建索引,则全表扫描

总结
type 类型从快到慢:system>const>eq_ref>ref>range>index>ALL
作为一名合格的后端开发者应该熟悉掌握 Explain
结合业务建立正确索引,而不是每个字段建立索引(滥用)

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部