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;

因为 agename 都在索引 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
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐