qinyelin
发布于 2026-09-02 / 4 阅读
0
0

MySQL EXPLAIN 执行计划

面试频率:★★★★★
工作频率:★★★★★


⚡ 30 秒速记

EXPLAIN 用来查看:

MySQL 准备如何执行一条 SQL。

例如:

EXPLAIN
SELECT *
FROM user
WHERE name = '张三';

常见结果:

id
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra

刚开始不用全部背。

先重点掌握:

type

possible_keys

key

rows

Extra

简单记:

type
↓
怎么查

possible_keys
↓
可能用哪些索引

key
↓
实际选择哪个索引

rows
↓
预计检查多少行

Extra
↓
额外执行信息

分析顺序:

EXPLAIN
   ↓
type
   ↓
key
   ↓
rows
   ↓
Extra

一、EXPLAIN 是什么?

平时执行:

SELECT *
FROM user
WHERE name = '张三';

我们可能会猜:

会不会走idx_name?

会不会全表扫描?

会扫描多少数据?

会不会回表?

不要靠猜。

可以:

EXPLAIN
SELECT *
FROM user
WHERE name = '张三';

让 MySQL 告诉我们:

它准备怎么执行这条SQL

所以:

EXPLAIN 是分析 SQL 执行计划的重要工具。


二、先看哪几个字段?

刚开始重点掌握:

type

possible_keys

key

rows

Extra

以后看到:

EXPLAIN结果

先按照:

type
 ↓
key
 ↓
rows
 ↓
Extra

分析。


三、possible_keys

possible_keys 表示:

MySQL 优化器认为这条 SQL 可能使用哪些索引。

例如:

possible_keys = idx_name

说明:

优化器发现

idx_name

可能可以用于这条SQL

但是:

possible_keys有索引

不代表:

最终一定使用这个索引

四、key

key 表示:

MySQL 最终实际选择使用的索引。

例如:

possible_keys = idx_name

key = idx_name

说明:

候选:

idx_name

↓

最终:

idx_name

也就是:

实际使用了idx_name

如果:

key = NULL

通常说明:

没有选择索引

可能:

全表扫描

但最终还要结合:

type

一起看。


五、possible_keys 和 key 的区别

这个面试经常问。

possible_keys

=

理论上可能使用的索引
key

=

最终实际选择的索引

例如:

possible_keys = idx_name, idx_age

key = idx_name

说明:

优化器发现:

idx_name
idx_age

都有可能

但是最终认为:

idx_name成本更低

所以:

选择idx_name

六、判断有没有走索引看哪个?

重点看:

key

不要只看:

possible_keys

因为:

possible_keys有值

可能:

key = NULL

也就是:

虽然存在候选索引

↓

但是优化器最终没选

七、type 是什么?

type 是 EXPLAIN 中非常重要的字段。

表示:

MySQL 使用什么方式访问表中的数据。

常见访问类型可以先这样记:

system
 ↓
const
 ↓
eq_ref
 ↓
ref
 ↓
range
 ↓
index
 ↓
ALL

通常:

越往上

↓

扫描范围越小
越往下

↓

扫描范围越大

注意:

这是一个方便记忆的常见顺序,不要机械理解成任何情况下上面的都绝对比下面快,实际性能还要结合数据量、rows、回表、SQL 等一起判断。


八、const

例如:

SELECT *
FROM user
WHERE id = 10;

假设:

id

是:

PRIMARY KEY

MySQL 可以通过:

主键索引

快速确定:

唯一一条数据

可能看到:

type = const

可以简单理解:

通过主键 / 唯一索引

↓

等值查询

↓

最多匹配非常少的数据

性能通常很好。


九、ref

例如:

CREATE INDEX idx_name
ON user(name);

查询:

SELECT *
FROM user
WHERE name = '张三';

因为:

name

是普通索引。

可能存在:

张三 id=10

张三 id=20

张三 id=50

也就是说:

一个name

↓

可能对应多条数据

可能:

type = ref

可以简单理解:

普通非唯一索引的等值查询中经常看到 ref。


十、range

例如:

SELECT *
FROM user
WHERE id > 100;

或者:

SELECT *
FROM user
WHERE id BETWEEN 100 AND 200;

可能:

type = range

表示:

索引范围扫描

可以理解:

找到100附近
   ↓
沿索引继续扫描
   ↓
直到200

这和我们之前学的:

B+ Tree叶子节点有序

正好对应。


十一、index

如果:

type = index

可以简单理解:

MySQL 扫描整个索引。

注意:

index

不代表:

性能一定很好

因为:

整个索引

可能也非常大。

例如:

1000万条索引记录

↓

全部扫描

一样可能很慢。

但是索引页通常比完整数据行更小,所以:

全索引扫描

某些情况下可能比:

全表扫描

成本低。


十二、ALL

这个一定要认识。

type = ALL

表示:

全表扫描。

例如:

SELECT *
FROM user
WHERE address = '杭州';

假设:

address没有索引

MySQL 可能:

第1行
 ↓
判断address

第2行
 ↓
判断address

第3行
 ↓

...

整张表

所以:

type = ALL

十三、看到 ALL 一定有问题吗?

不一定。

例如:

表里面只有20条数据

全表扫描:

20条

可能比:

走索引
+
回表

还简单。

所以:

type = ALL

不是看到就一定要优化。

还需要看:

rows

例如:

type = ALL

rows = 20

可能:

问题不大

但:

type = ALL

rows = 5000000

就需要:

重点关注

十四、type 怎么记?

先重点记这几个:

const
↓
主键 / 唯一索引等值查询常见


ref
↓
普通索引等值查询常见


range
↓
索引范围查询


index
↓
扫描整个索引


ALL
↓
扫描整张表

面试中通常:

至少尽量达到range

是一个常见的经验说法。

但是:

不能只根据 type 一个字段判断 SQL 性能。


十五、rows

rows 表示:

MySQL 优化器估计为了完成查询需要检查的行数。

例如:

rows = 10

说明预计:

检查大约10行

而:

rows = 1000000

说明预计:

检查大量数据

通常:

rows越小

↓

需要检查的数据越少

十六、rows 是真实扫描行数吗?

不是。

一定要记:

rows

=

优化器估算值

不是:

真实执行后精确扫描行数

所以:

rows = 10000

不是说:

一定刚好扫描10000行

十七、为什么 rows 很重要?

例如两条执行计划:

方案 A:

type = ref

key = idx_name

rows = 10

方案 B:

type = ALL

key = NULL

rows = 1000000

明显:

方案A

↓

预计检查的数据少很多

方案 B:

全表扫描

+

预计100万行

就值得重点关注。


十八、Extra

Extra 表示:

MySQL 执行 SQL 时的一些额外信息。

常见:

Using index

Using where

Using index condition

Using temporary

Using filesort

刚开始重点认识:

Using index

Using where

Using index condition

十九、Using index

例如:

CREATE INDEX idx_name_age
ON user(name, age);

查询:

SELECT name, age
FROM user
WHERE name = '张三';

查询需要:

name
age

索引:

(name,age)

已经全部包含。

所以:

不需要回表

可能:

Extra = Using index

通常表示:

查询需要的数据可以直接从索引中获取,也就是使用了覆盖索引。


二十、Using where

如果:

Extra = Using where

表示:

MySQL 还需要根据 WHERE 条件对读取到的记录进行过滤。

可以简单理解:

先读取候选数据

↓

再判断WHERE条件

↓

符合

↓

返回

注意:

Using where

不代表:

一定没走索引

可能:

key = idx_name

Extra = Using where

也就是:

使用了索引

+

还需要进行WHERE过滤

二十一、Using index condition

如果:

Extra = Using index condition

表示:

使用了ICP

Index Condition Pushdown

索引条件下推

简单理解:

原来:

索引找到候选记录
    ↓
回表
    ↓
再判断某些条件

ICP:

索引找到候选记录
    ↓
在索引层先过滤一部分
    ↓
减少不必要的回表

这个后面可以单独学习。

现在先记:

Using index condition

↓

索引下推 ICP

二十二、Using index 和 Using index condition 不一样

这个非常容易混。

Using index

通常:

覆盖索引

↓

查询数据直接从索引获得

↓

避免回表

而:

Using index condition

表示:

ICP索引下推

↓

在索引层提前过滤

↓

减少回表

所以:

Using index
≠
Using index condition

二十三、完整案例1:主键查询

SQL:

EXPLAIN
SELECT *
FROM user
WHERE id = 10;

可能:

type = const

possible_keys = PRIMARY

key = PRIMARY

rows = 1

分析:

possible_keys = PRIMARY
↓
主键索引可以使用


key = PRIMARY
↓
实际使用主键索引


type = const
↓
唯一等值定位


rows = 1
↓
预计只检查极少数据

整体:

很好

二十四、完整案例2:普通索引

索引:

CREATE INDEX idx_name
ON user(name);

SQL:

EXPLAIN
SELECT *
FROM user
WHERE name = '张三';

可能:

type = ref

possible_keys = idx_name

key = idx_name

rows = 5

分析:

type = ref
↓
普通索引等值查询


key = idx_name
↓
实际使用idx_name


rows = 5
↓
预计匹配少量数据

二十五、完整案例3:范围查询

SQL:

EXPLAIN
SELECT *
FROM user
WHERE id BETWEEN 100 AND 200;

可能:

type = range

key = PRIMARY

rows = 100

分析:

PRIMARY
↓
使用主键索引


range
↓
范围扫描


rows
↓
预计检查一定范围的数据

二十六、完整案例4:全表扫描

SQL:

EXPLAIN
SELECT *
FROM user
WHERE address = '杭州';

假设:

address没有索引

可能:

type = ALL

possible_keys = NULL

key = NULL

rows = 1000000

Extra = Using where

分析:

type = ALL
↓
全表扫描


key = NULL
↓
没有使用索引


rows = 1000000
↓
预计检查100万行


Using where
↓
还要判断address条件

这种:

值得重点关注

二十七、分析 EXPLAIN 的顺序

以后不要看到一堆字段就乱。

直接按照:

第一步:

type
↓
怎么访问数据?

然后:

第二步:

key
↓
实际使用哪个索引?

然后:

第三步:

rows
↓
预计检查多少行?

最后:

第四步:

Extra
↓
有没有覆盖索引?
有没有额外过滤?
有没有ICP?

可以记:

type
 ↓
key
 ↓
rows
 ↓
Extra

二十八、看到什么情况要警觉?

例如:

type = ALL

key = NULL

rows = 3000000

意味着:

全表扫描

+

没有使用索引

+

预计检查300万行

这种通常:

值得重点分析

但是:

type = ALL

key = NULL

rows = 10

表只有:

10条数据

那么:

可能完全没必要优化

所以:

EXPLAIN 一定要结合数据量分析,不能机械背规则。


二十九、EXPLAIN 和索引失效的关系

之前我们学:

函数

隐式类型转换

LIKE前导%

最左匹配

低选择性

这些只是告诉你:

可能影响索引使用

最终到底有没有走:

不要猜

直接:

EXPLAIN SQL;

然后看:

type

key

rows

Extra

所以:

索引理论
   ↓
判断可能情况
   ↓
EXPLAIN
   ↓
验证实际执行计划

三十、和前面知识串起来

现在 MySQL 索引这条线:

B+ Tree
   ↓
为什么索引查询快
   ↓
聚簇索引 / 二级索引
   ↓
回表
   ↓
覆盖索引
   ↓
联合索引
   ↓
最左匹配
   ↓
索引失效
   ↓
EXPLAIN
   ↓
验证SQL到底怎么执行

以后拿到一条 SQL:

SELECT age
FROM user
WHERE name = '张三';

索引:

INDEX(name, age)

你可以分析:

第一层:

name满足最左匹配
↓
可以利用联合索引定位


第二层:

name + age都在索引
↓
覆盖索引
↓
不用回表


第三层:

EXPLAIN
↓
验证执行计划

这样整个知识就串起来了。


🎤 面试回答

问:

EXPLAIN 是干什么的?

答:

EXPLAIN 用来查看 MySQL 的 SQL 执行计划,可以帮助我们分析 SQL 的访问方式、可能使用的索引、实际使用的索引、预计扫描行数以及其他执行信息。

分析 EXPLAIN 时我通常会重点关注:

type

possible_keys

key

rows

Extra

其中:

type

表示访问方式;

possible_keys

表示可能使用的索引;

key

表示最终实际选择的索引;

rows

表示优化器预计需要检查的行数;

Extra

可以看到覆盖索引、额外过滤、索引下推等信息。


🎯 面试追问

Q1:possible_keys 和 key 有什么区别?

答:

possible_keys

↓

可能使用的索引
key

↓

最终实际选择的索引

Q2:判断有没有走索引主要看什么?

答:

key

如果:

key = NULL

通常说明:

没有选择索引

还要结合:

type

判断访问方式。


Q3:type = ALL 是什么意思?

答:

全表扫描

Q4:type = index 是什么意思?

答:

扫描整个索引

注意:

index
≠
一定很快

因为:

可能扫描大量索引记录

Q5:type = range 是什么意思?

答:

索引范围扫描

例如:

WHERE id BETWEEN 100 AND 200;

Q6:type = ref 是什么意思?

答:

普通非唯一索引:

等值查询

中经常出现。

例如:

WHERE name = '张三';

Q7:type = const 是什么意思?

答:

主键或唯一索引:

等值查询

并且可以快速确定极少数据时经常出现。


Q8:rows 是实际扫描行数吗?

答:

不是

它是:

优化器估算需要检查的行数

Q9:Using index 是什么意思?

答:

通常表示:

覆盖索引

↓

查询需要的数据可以直接从索引取得

↓

避免回表

Q10:Using where 是什么意思?

答:

表示:

读取数据以后

↓

还需要根据WHERE条件过滤

它不代表:

一定没使用索引

Q11:Using index condition 是什么意思?

答:

表示:

ICP

Index Condition Pushdown

索引条件下推

作用:

在索引层提前过滤

↓

减少不必要的回表

Q12:Using index 和 Using index condition 一样吗?

答:

不一样
Using index

↓

通常表示覆盖索引
Using index condition

↓

表示索引下推ICP

Q13:看到 type = ALL 就一定要优化吗?

答:

不一定

还要看:

rows

表的数据量

查询场景

如果:

表只有几十条数据

全表扫描可能完全没问题。


⚠️ 易错点

1. possible_keys 有值 ≠ 实际走索引

例如:

possible_keys = idx_name

key = NULL

说明:

idx_name虽然可以作为候选

↓

但优化器最终没有选择

2. key 才是最终选择的索引

所以判断:

实际走哪个索引

重点看:

key

3. type = index 不是普通意义上的“走索引就很快”

它表示:

扫描整个索引

所以:

1000万条索引记录

↓

还是可能扫描很多数据

4. type = ALL 不一定就是垃圾 SQL

如果:

表非常小

全表扫描:

可能就是最优方案

5. rows 不是精确值

rows

=

优化器估算

不是:

实际扫描行数

6. Using where 不代表没走索引

可能:

key = idx_name

Extra = Using where

说明:

使用索引

+

仍然需要WHERE过滤

7. EXPLAIN 不能只看一个字段

不要:

看到key有值
↓
SQL一定很好

也不要:

看到ALL
↓
SQL一定很差

应该综合:

type

key

rows

Extra

数据量

SQL业务场景

判断。


❓ 自测

  1. EXPLAIN 是干什么的?

  2. EXPLAIN 最重要的几个字段有哪些?

  3. possible_keys 是什么意思?

  4. key 是什么意思?

  5. possible_keys 和 key 有什么区别?

  6. 判断实际使用哪个索引主要看哪个字段?

  7. key = NULL 通常代表什么?

  8. type 是什么意思?

  9. type = const 是什么意思?

  10. type = ref 是什么意思?

  11. type = range 是什么意思?

  12. type = index 是什么意思?

  13. type = ALL 是什么意思?

  14. index 和 ALL 有什么区别?

  15. type = ALL 一定需要优化吗?

  16. rows 是什么意思?

  17. rows 是真实扫描行数吗?

  18. rows 很大意味着什么?

  19. Extra 是干什么的?

  20. Using index 是什么意思?

  21. Using where 是什么意思?

  22. Using where 是否代表没有走索引?

  23. Using index condition 是什么意思?

  24. Using index 和 Using index condition 有什么区别?

  25. 为什么 possible_keys 有索引,key 还可能是 NULL?

  26. 为什么字段有索引,优化器还可能不使用?

  27. 分析 EXPLAIN 推荐按照什么顺序?

  28. type=ALL、key=NULL、rows=3000000 为什么值得关注?

  29. 为什么不能只根据 type 判断 SQL 性能?

  30. EXPLAIN 和索引失效有什么关系?


评论