MySQL 查询计划详解

发布于 2026-07-30 20:18 更新于 2026-07-30 20:18 1887 字 10 min read ... 访问量

本文详细介绍了 MySQL 中 EXPLAIN 查询计划的使用方法和各列含义,帮助用户分析 SQL 语句的执行过程。通过查看执行计划,可以判断访问类型、索引选择、扫描行数及是否需要优化,重点分析了 id、type、key、rows、filtered 等关键字段,并强调了结合实际执行数据(如 EXPLAIN ANALYZE)进行性能评估的重要性。

MySQL EXPLAIN 查询计划详解

EXPLAIN 用于查看 MySQL 为一条 SQL 语句生成的执行计划。通过执行计划可以分析访问顺序、索引选择、预估扫描行数以及排序、临时表等信息。

DESCEXPLAIN 的区别

查看表结构

DESCDESCRIBE 的缩写,用于查看表或视图的字段信息。

DESC employee;

DESCRIBE employee;

这两条语句通常会显示字段名、数据类型、是否允许为 NULL、索引类型、默认值和附加信息。

查看 SQL 执行计划

在查询语句前添加 EXPLAIN,可以查看优化器选择的执行计划。

EXPLAIN
SELECT *
FROM employee
WHERE first_name = 'tom';
image-001
image-001

MySQL 还支持其他输出格式。例如,树形格式更便于观察执行顺序:

EXPLAIN FORMAT=TREE
SELECT *
FROM employee
WHERE first_name = 'tom';

EXPLAIN ANALYZE 会实际执行 SQL,并返回估算值与实际执行数据。对于更新或删除语句应谨慎使用,避免意外修改数据。

EXPLAIN ANALYZE
SELECT *
FROM employee
WHERE first_name = 'tom';

EXPLAIN 常见列

image-002
image-002

传统表格格式通常包含以下列:

列名作用
id查询块编号,可辅助判断查询块之间的执行关系
select_type查询块的类型,例如简单查询、主查询、子查询或派生表
table当前访问的表、别名或内部临时结果
partitions预计访问的分区;未使用分区表时通常为 NULL
type表访问方式,是判断索引使用情况的重要指标
possible_keys优化器认为可能使用的索引
key实际选择的索引
key_len预计使用的索引键长度,单位为字节
ref与索引列比较的常量或列
rows优化器估算需要检查的行数
filtered经过当前表条件过滤后预计保留的百分比
Extra排序、临时表、覆盖索引等补充信息

id:查询块编号

id 用于标识不同的查询块,但不能简单地把它当作绝对执行顺序。

  • id 相同的多行通常属于同一个查询块,表的显示顺序反映该连接计划中的访问顺序。
  • id 不同通常表示存在子查询、派生表或 UNION 等多个查询块。
  • 某些结果行的 id 可能为 NULL,例如 UNION RESULT

复杂 SQL 的真实执行过程还应结合 FORMAT=TREEEXPLAIN ANALYZE 判断。

select_type:查询类型

常见取值如下:

取值含义
SIMPLE不包含 UNION 或子查询的简单查询
PRIMARY最外层查询
UNIONUNION 中第二个及后续查询块
DEPENDENT UNION依赖外层查询结果的 UNION 查询块
UNION RESULTUNION 结果集
SUBQUERY不依赖外层查询的子查询
DEPENDENT SUBQUERY依赖外层查询结果的相关子查询
DERIVEDFROM 子句中的派生表
MATERIALIZED被物化后重复使用的子查询结果

table:访问对象

table 一般显示表名或表别名。对于优化器生成的内部结果,可能出现以下形式:

  • <derivedN>:来自编号为 N 的派生表查询块。
  • <unionM,N>:来自编号为 MN 等查询块的 UNION 结果。
  • <subqueryN>:被物化的子查询结果。

type:访问方式

type 描述 MySQL 如何从表中读取数据。下面按通常情况下由精确到宽泛的顺序列出常见类型,但实际性能还受返回行数、数据分布和缓存等因素影响。

类型说明
system表被视为只有一行,是 const 的特例
const通过主键或唯一索引等值匹配,最多返回一行
eq_ref连接时通过主键或非空唯一索引匹配,每个前表组合最多命中一行
ref通过普通索引或唯一索引的非完整前缀进行等值查找,可能返回多行
fulltext使用全文索引
ref_or_null类似 ref,同时额外查找 NULL
index_merge合并多个索引的扫描结果
unique_subquery某些 IN 子查询通过唯一索引查找
index_subquery某些 IN 子查询通过非唯一索引查找
range对索引执行范围扫描
index扫描整个索引
ALL扫描整张表

分析时通常需要重点关注 ALLindex。不过小表全表扫描不一定是问题,不能只根据 type 单独判断 SQL 是否需要优化。

索引相关列

possible_keys

显示优化器认为可能使用的索引。值为 NULL 表示当前查询没有明显可用索引,但这并不等同于 SQL 一定存在性能问题。

key

显示优化器最终选择的索引。即使 possible_keys 列出了多个索引,key 通常也只显示实际采用的索引;使用 index_merge 时可能显示多个索引。

key_len

显示执行计划预计使用的索引键长度。对于联合索引,可以根据该值辅助判断使用到了哪些索引列。

key_len 是估算的最大长度,不代表实际读取的数据长度。字符集、可空列、变长字段和索引列类型都会影响该值。

ref

显示索引查找时用于比较的值。例如:

  • const:与常量比较。
  • 库名.表名.列名:与另一张表的列比较。
  • func:与表达式、函数结果或发生类型转换的值比较。

rowsfiltered

rows

rows 是优化器估算需要检查的行数,并非实际扫描行数。统计信息不准确时,估算结果也可能出现偏差。

filtered

filtered 是预计通过当前表条件过滤后保留的数据比例,单位为百分比。

可以用下面的方式粗略估算传递给下一步的行数:

rows × filtered ÷ 100

若需要观察实际执行行数和耗时,应使用 EXPLAIN ANALYZE

Extra:补充信息

Extra 中常见信息如下:

信息说明
Using index使用覆盖索引即可获得所需列,通常不需要回表
Using where读取数据后还需要根据条件进行过滤
Using index condition使用索引条件下推,在存储引擎层过滤部分记录
Using filesort排序无法直接利用合适的索引,需要额外排序;不一定真的写磁盘文件
Using temporary使用内部临时表保存中间结果,常见于部分分组、去重或排序操作
Using join buffer连接过程使用连接缓冲区,通常需要检查连接条件和索引
FirstMatch半连接优化策略之一,找到首个匹配后停止继续查找
LooseScan半连接优化策略之一,通过索引跳跃扫描减少重复匹配
Impossible WHERE优化器判断查询条件不可能成立

Extra 可以同时出现多项信息。例如:

Using index condition; Using where

基本分析思路

分析执行计划时,可以按以下顺序检查:

  1. 确认表的访问顺序是否合理。

  2. 检查 type 是否出现大表的 ALL 或不必要的 index 扫描。

  3. 对比 possible_keyskey,确认索引是否被选中。

  4. 结合 key_len 判断联合索引的使用范围。

  5. 关注 rowsfilteredExtra 中的排序、临时表及连接缓冲信息。

  6. 对关键 SQL 使用 EXPLAIN ANALYZE,以实际行数和耗时验证估算结果。

喜欢的话,留下你的评论吧~

... 访问量
© 2026 跨越星轨的客 @Hoshiumi
Powered by theme astro-koharu · Inspired by Shoka