《Explain 执行计划详解:SQL 性能瓶颈与索引命中分析》


一、前言:为什么要用 Explain

大家好,我是程序员卷卷狗。

在 MySQL 中,SQL 的执行效率取决于优化器的决策。
优化器会根据表结构、索引、统计信息,选择一条“最优路径”去执行查询。

我们可以用 EXPLAIN 查看优化器选择的执行方案,
从而判断:

  • SQL 是否使用索引;
  • 是否走全表扫描;
  • 哪个表先被连接;
  • 过滤行数预估是多少。

一句话:

EXPLAIN 是读懂 SQL 性能瓶颈的第一步。


二、Explain 基本语法

EXPLAIN SELECT * FROM user WHERE age > 18;

或更详细版本:

EXPLAIN FORMAT=JSON SELECT * FROM user WHERE age > 18;

常见输出字段

字段名 含义
id 查询执行顺序(越大越先执行)
select_type 查询类型(简单查询/子查询/联合查询)
table 当前访问的表
partitions 使用的分区(若有)
type 连接类型(访问方式)
possible_keys 可能用到的索引
key 实际使用的索引
key_len 索引长度
ref 索引匹配的列
rows 预估扫描行数
filtered 过滤比例
Extra 额外信息(最关键)

三、type 字段:判断访问效率

type 表示 MySQL 如何访问数据,是最重要的指标。

值(从优到劣) 含义 示例
system 只有一行数据 特殊情况
const 主键或唯一索引等值查询 WHERE id=1
eq_ref 联表时主键匹配 JOIN 场景
ref 非唯一索引等值匹配 WHERE name='卷卷狗'
range 范围扫描 WHERE age>20
index 全索引扫描 只访问索引,不访问表
ALL 全表扫描 最低效

记忆口诀:

system → const → eq_ref → ref → range → index → ALL
→ 越靠前越好。

示例对比:
EXPLAIN SELECT * FROM user WHERE id=1;
-- type: const ✅
EXPLAIN SELECT * FROM user WHERE age>20;
-- type: range ⚠️
EXPLAIN SELECT * FROM user;
-- type: ALL ❌

四、key 与 possible_keys:索引使用情况

字段 说明
possible_keys 优化器认为“可能可用”的索引
key 实际被使用的索引
示例:
EXPLAIN SELECT * FROM user WHERE name='卷卷狗';

输出:

possible_keys: idx_name
key: idx_name

→ 索引命中成功。

key 为空:

possible_keys: idx_name
key: NULL

→ 索引未被使用,需检查:

  • 是否类型不匹配;
  • 是否函数作用在列上;
  • 是否联合索引失效。

五、rows 与 filtered:扫描代价估算

字段 含义
rows 预估扫描行数(越少越好)
filtered 过滤比例(0~100%)

例如:

rows: 10000
filtered: 10

表示优化器预估会扫描 1 万行,其中 10% 能通过过滤。

关键启示:
如果 rows 太大,说明索引选择性差,需要优化。


六、Extra 字段:隐藏的性能信号

Extra 提供额外优化信息,
是判断是否“真正走索引”的关键。

Extra 含义 说明
Using index 覆盖索引(不回表) ✅
Using index condition 索引下推(ICP 优化) ✅
Using where 使用 where 过滤(可能未走索引) ⚠️
Using temporary 使用临时表(排序/分组代价大) ❌
Using filesort 文件排序(未命中索引排序) ❌
Using join buffer JOIN 时使用缓存(无索引) ⚠️
Impossible where WHERE 条件恒 false
Using MRR 多范围读取(优化 IO) ✅

出现 “Using index” 是性能最好的信号。
“Using filesort” 通常是性能瓶颈的标志。


七、Explain 优化思路(五步法)

① 看 type(访问方式)
  • 是否为 constrefrange
  • 若为 ALL,说明未走索引。
② 看 key(实际索引)
  • 检查是否命中正确索引;
  • 若空,考虑索引设计或条件改写。
③ 看 rows(扫描行数)
  • 行数大说明过滤不精准;
  • 可通过添加索引或优化条件减少扫描量。
④ 看 Extra(执行细节)
  • 避免 Using filesortUsing temporary
  • 确保出现 Using indexUsing index condition
⑤ 验证 SQL 改写效果
  • 使用 ANALYZE TABLE 更新统计信息;
  • 再次 EXPLAIN 观察优化效果。

八、实际案例:索引优化前后对比

表结构:
CREATE TABLE user (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  age INT,
  INDEX idx_name_age (name, age)
);
优化前:
EXPLAIN SELECT * FROM user WHERE age>20;

输出:

type: ALL
rows: 100000
Extra: Using where

→ 未走索引,全表扫描。

优化后:
EXPLAIN SELECT * FROM user WHERE name='卷卷狗' AND age>20;

输出:

type: range
key: idx_name_age
rows: 120
Extra: Using index condition

→ 命中联合索引,性能大幅提升。


九、面试高频问题与答题模板

问题 答案要点
Q1:EXPLAIN 的作用是什么? 查看 SQL 执行计划,分析是否走索引。
Q2:type 字段代表什么? 表示访问方式,从 const 到 ALL 性能递减。
Q3:possible_keys 与 key 的区别? 前者是可用索引,后者是实际使用索引。
Q4:rows 越大说明什么? 扫描行数多,索引不精准。
Q5:Extra 中哪些是性能警告? Using filesort、Using temporary。
Q6:如何判断走了覆盖索引? Extra 出现 Using index。
Q7:如何改写 SQL 提升 type 等级? 优化索引结构、避免函数、改写 WHERE 顺序。

十、总结

EXPLAIN 是 SQL 优化的“放大镜”,
它能揭示每条语句的执行细节与瓶颈所在。

一句话记住:

看 type 判路径,看 key 判命中,看 Extra 判代价。

掌握这三个核心指标,就能判断 SQL 是否真正高效。

下一篇(第 16 篇),我将写——
《MySQL 慢查询优化:从定位、分析到索引调优的完整流程》
手把手讲清楚如何使用 slow_query_log、EXPLAIN、优化重写 SQL。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐