【Mysql】执行计划的分析---Type本质
type 不是看 select 后面的字段,也不是单纯看 where 后面的字段。
更准确地说:
type看的是:MySQL 访问这张表时,采用了什么“找数据的方式”。
也就是:MySQL 是怎么从表里把数据找出来的。
先抓住一句话
select 后面的字段:主要影响是否回表、是否覆盖索引
where / join / order by 后面的字段:主要影响能不能用索引、用什么方式访问表
type:是 MySQL 最终选择的访问方式
所以你看到有人说看 select 后面的字段,有人说看 where 后面的字段,是因为它们都会影响执行计划,但影响点不一样。
一、type 主要和 where / join 条件有关
比如有表:
user(id, name, age, city)
其中:
id 是主键
age 有普通索引
name 没有索引
1. 根据主键查:type = const
explain select * from user where id = 1;
因为 id 是主键,id = 1 最多只能查到一条数据。
所以:
type = const
key = PRIMARY
这里 type 是由:
where id = 1
决定的。
也就是:MySQL 通过主键索引一次定位。
2. 根据普通索引查:type = ref
explain select * from user where age = 18;
age 是普通索引,age = 18 可能查出很多人。
所以:
type = ref
key = idx_age
这里 type 也是由:
where age = 18
决定的。
3. 根据范围查:type = range
explain select * from user where age > 18;
因为是范围查询,所以:
type = range
key = idx_age
4. 没有索引:type = ALL
explain select * from user where name = '张三';
如果 name 没有索引,MySQL 只能全表扫描:
type = ALL
key = NULL
所以大多数情况下,type 主要看的是:
where 后面的条件有没有索引
where 后面的条件是等值还是范围
where 后面的条件用的是主键、唯一索引还是普通索引
二、那 select 后面的字段影响什么?
select 后面的字段一般不直接决定 type 的核心类型,但它会影响:
是否需要回表
是否能用覆盖索引
是否只扫描索引就够了
看这个例子。
假设有联合索引:
index idx_age_name(age, name)
情况 1:select 的字段都在索引里
explain select age, name from user where age = 18;
因为 age 和 name 都在索引 idx_age_name 里面,所以 MySQL 只看索引就能得到结果。
可能是:
type = ref
key = idx_age_name
Extra = Using index
这里:
type = ref
是因为 where age = 18 使用普通索引等值查询。
而:
Extra = Using index
是因为 select age, name 这两个字段都在索引里,不用回表。
情况 2:select 了索引里没有的字段
explain select age, name, city from user where age = 18;
如果 city 不在索引里,MySQL 先通过 idx_age_name 找到符合 age = 18 的记录,然后还要回到主键索引里拿 city。
可能是:
type = ref
key = idx_age_name
Extra = Using where
你会发现:
type 仍然可能是 ref
但是 Extra 变了,不能做到覆盖索引了。
所以:
select后面的字段主要影响Extra里的Using index,以及是否回表。
三、为什么有时候 select 后面的字段会影响 type?
因为有一种特殊情况:如果查询的字段刚好都在某个索引里,MySQL 可能会选择扫描索引,而不是扫描整张表。
比如:
explain select age from user;
如果 age 有索引,那么 MySQL 可能会扫描 age 这个索引:
type = index
key = idx_age
Extra = Using index
注意这个 SQL 没有 where:
select age from user;
那为什么还能用索引?
因为你只查询 age,而 age 本身就在索引里,MySQL 直接扫描索引就够了。
这时 type = index。
它的意思是:
扫描整棵索引树,而不是扫描整张表。
再看:
explain select * from user;
如果查所有字段,索引里不包含所有字段,MySQL 通常只能扫描整张表:
type = ALL
key = NULL
所以你会看到:
select age from user;
可能是:
type = index
而:
select * from user;
可能是:
type = ALL
这就是为什么有人说 select 后面的字段也会影响 type。
但本质不是因为 select 字段在“筛选数据”,而是因为:
select 的字段决定了 MySQL 能不能只扫描索引完成查询。
四、用一句话区分 select 和 where 的作用
where 后面的字段
负责回答:
怎么找数据?
能不能通过索引快速定位?
是等值查、范围查,还是全表扫?
所以它主要影响:
type
key
rows
例如:
where id = 1 -> const
where age = 18 -> ref
where age > 18 -> range
where name = '张三' 且 name 无索引 -> ALL
select 后面的字段
负责回答:
找到数据后,需要取哪些列?
这些列索引里有没有?
需不需要回表?
所以它主要影响:
Extra
是否 Using index
是否回表
有时候也会让 type 从 ALL 变成 index
例如:
select age from user;
如果 age 有索引,可以只扫索引:
type = index
Extra = Using index
但:
select * from user;
可能只能扫全表:
type = ALL
五、你可以这样判断 type
以后你看 type,可以按这个顺序想:
第一步:where / join 条件有没有索引?
没有索引,大概率:
type = ALL
有索引,继续看。
第二步:用的是主键还是唯一索引?
where id = 1
如果 id 是主键:
type = const
JOIN 中如果用主键/唯一索引关联:
type = eq_ref
第三步:用的是普通索引等值查询?
where age = 18
如果 age 是普通索引:
type = ref
第四步:用的是索引范围查询?
where age > 18
where age between 18 and 30
where age in (...)
可能是:
type = range
第五步:没有 where,但 select 的字段都在索引里?
select age from user;
如果 age 有索引:
type = index
表示扫描整棵索引树。
第六步:什么索引都用不上?
select * from user;
select * from user where name = '张三'; -- name 无索引
大概率:
type = ALL
表示全表扫描。
六、举一个完整对比
假设:
user(
id int primary key,
name varchar(50),
age int,
city varchar(50),
index idx_age(age),
index idx_age_name(age, name)
)
例 1
select * from user where id = 1;
分析:
where id = 1
id 是主键
最多一条数据
所以:
type = const
例 2
select * from user where age = 18;
分析:
where age = 18
age 是普通索引
可能有多行
所以:
type = ref
例 3
select * from user where age > 18;
分析:
where age > 18
age 是索引
范围查询
所以:
type = range
例 4
select * from user where city = '北京';
分析:
city 没有索引
无法快速定位
所以:
type = ALL
例 5
select age from user;
分析:
没有 where
但是 age 在 idx_age 索引里
只需要扫描索引即可
所以:
type = index
Extra = Using index
例 6
select * from user;
分析:
没有 where
select * 需要所有字段
不能只靠普通索引完成
所以:
type = ALL
七、最容易混淆的点
你可能疑惑的是:
select age from user;
这里明明没有 where,为什么 type 还能是 index?
因为 type = index 不是“根据索引查某几条数据”,而是:
扫描整棵索引树。
它不是精确查找,只是扫描对象从“表”变成了“索引”。
所以:
type = index
并不一定特别优秀。
它只是比:
type = ALL
通常好一些。
八、最终总结
type 本质看的是:
MySQL 访问这张表的方式。
一般情况下:
where / join 条件决定 MySQL 能不能快速定位数据,所以主要影响 type。
但是:
select 后面的字段决定 MySQL 要取哪些列,如果这些列都在索引里,MySQL 可能只扫描索引,所以有时也会影响 type。
你可以记成:
where 决定怎么找;
select 决定找完以后取什么;
type 反映最终怎么访问表。
最常见判断:
主键等值查询 -> const
唯一索引 JOIN -> eq_ref
普通索引等值查询 -> ref
索引范围查询 -> range
扫描整个索引 -> index
扫描整张表 -> ALL
更多推荐




所有评论(0)