MySQL EXPLAIN 完全解读:从执行计划到索引优化

前言

在 MySQL 数据库调优中,EXPLAIN 是开发者最强大的"照妖镜"。任何 SELECT 查询,只要在前面加上 EXPLAIN,MySQL 就会告诉你它打算怎么执行这条 SQL------用哪些索引、联表顺序、扫描多少行、有没有隐性问题。

本文将从实际开发视角,逐一拆解 EXPLAIN 输出中的每个字段,并给出可直接落地的优化判断标准。


一、EXPLAIN 是什么?

执行 EXPLAIN SELECT ... 后,MySQL 不会真实执行查询,而是返回执行计划,以表格形式展示每一步如何操作。

sql

复制代码
EXPLAIN SELECT * FROM user WHERE id = 1;

输出一行或多行,每一行代表一个步骤(单表访问、子查询、UNION 等)。


二、字段详解(按重要性排序)

1. id ------ 步骤编号

  • 数字越大,越先执行

  • 数字相同,从上往下执行

  • NULL:最后合并步骤(如 UNION)

子查询不一定比主查询后执行,DERIVED 表反而先执行。


2. select_type ------ 查询类型

含义 性能警示
SIMPLE 简单查询,无子查询、无UNION ✅ 正常
PRIMARY 外层主查询 -
SUBQUERY 普通子查询 ⚠️ 可能慢
DERIVED FROM 中的子查询(派生表) ⚠️ 一般慢
UNION UNION 中第二个及之后的查询 ⚠️
DEPENDENT SUBQUERY 相关子查询(依赖外层) ❌ 极慢,必须改 JOIN
UNCACHEABLE SUBQUERY 每次执行都要重算 ❌ 极慢

重点关注DEPENDENT SUBQUERY 是性能杀手,几乎都应改写为 JOIN。


3. table ------ 访问对象

可以是真实表名,也可能是 <derived2>(id=2 的派生表)或 <union1,2>


4. type ------ 访问类型 ★★★★

最重要的字段之一 ,直接反映索引使用效率。性能从好到差

级别 含义 说明
system 表只有一行 系统表,极少见
const 主键/唯一索引等值查询 极快,最多匹配一行
eq_ref 联表时被驱动表用主键/唯一索引 联表最优
ref 普通索引等值查询
range 索引范围查询(>, <, IN, BETWEEN) 尚可
index 扫描整个索引树 比全表快一点,但仍需回表
ALL 全表扫描 ❌ 最差,大表必崩

优化红线type = ALL 且表数据量 > 10万行,必须加索引


5. possible_keys ------ 可能使用的索引

列出候选索引。若为 NULL ,说明该表无可用索引,必须创建。


6. key ------ 实际使用的索引 ★★★★

  • NULL:没走索引

  • 需与 possible_keys 对比:有时明明有索引,MySQL 却不选(原因见 Extra)


7. key_len ------ 使用的索引长度(字节)

关键作用 :判断联合索引用到了几列

示例 :联合索引 (a, b, c)

  • key_len = 4:只用到了 a(INT)

  • key_len = 8:用到了 a、b(均为 INT)

  • key_len = 13:用到了 a、b、c(INT + INT + VARCHAR(10))

常见类型长度参考(utf8mb4):

  • INT:4 字节

  • BIGINT:8

  • VARCHAR(100):100 * 4 + 2 = 402 字节

  • DATETIME:5(5.6+)、8(旧版)


8. ref ------ 与索引比较的对象

  • const:常量(如 WHERE id = 1

  • db.table.column:联表时的另一张表列

  • NULL:不是等值查询


9. rows ------ 预计扫描行数 ★★★★

MySQL 估算值,非精确数值越大,查询越慢。优化目标就是让 rows 持续变小。


10. filtered ------ 过滤后剩余比例(%)

存储引擎返回后,经过 WHERE 条件过滤还剩下的比例。越低越好,说明索引筛选能力强。

示例:rows = 1000, filtered = 10 → 预计最终返回 100 行。


11. Extra ------ 额外信息 ★★★★★

最重要的补充说明直接暴露性能陷阱

✅ 好信号
含义
Using index 覆盖索引,不回表,极快
Using where 有 WHERE 条件过滤
⚠️ 警告信号(需优化)
含义 处理建议
Using index condition 索引条件下推(ICP) 尚可,但可检查索引顺序
Using temporary 用了临时表 ❌ GROUP BY 无索引,必须改
Using filesort 文件排序(内存/磁盘) ❌ ORDER BY 无索引,必须加
Using join buffer 联表无索引,用缓存 ❌ 必须为被驱动表加索引
❌ 危险信号
含义
Using temporary; Using filesort GROUP BY + ORDER BY 完全没走索引
Impossible WHERE WHERE 条件永远为假
No tables used 无 FROM 表

三、实战:5 分钟定位慢查询

拿到一条慢 SQL,按以下顺序逐列审查 EXPLAIN 结果:

第一步:先看 type

  • const/eq_ref/ref → 安全

  • ⚠️ range → 尚可

  • index/ALL必须优化

第二步:再看 key

  • 为 NULL → 没索引,立即加

  • 不为 NULL → 检查是否选对了索引

第三步:看 Extra

  • 出现 filesort/temporary/join buffer必须优化

  • 出现 Using index → 优秀

第四步:估算 rows

  • 预期只返回几条,但 rows 显示几万 → 索引失效或没走对索引

四、典型案例优化全过程

🚨 原始慢查询

sql

复制代码
EXPLAIN 
SELECT * FROM order 
WHERE user_id = 123 
ORDER BY create_time DESC;

执行计划

  • type: ALL(全表扫描)

  • rows: 500000

  • Extra: Using filesort(文件排序)

  • key: NULL

结论 :全表扫 50 万行,再在内存排序 → 极慢


✅ 添加索引

sql

复制代码
ALTER TABLE order ADD INDEX idx_user_time (user_id, create_time);

🚀 优化后执行计划

sql

复制代码
EXPLAIN 
SELECT * FROM order 
WHERE user_id = 123 
ORDER BY create_time DESC;
  • type: ref(走索引)

  • key: idx_user_time

  • rows: 15

  • Extra: Using index condition(无 filesort)

效果 :50万行扫描 → 15行,排序消失。


五、总结:EXPLAIN 优化口诀

text

复制代码
EXPLAIN 看计划,逐行拆开查:
type 是关键,ALL 是红线;
key 不为空,才算走索引;
rows 尽量小,越大越危险;
Extra 藏魔鬼,temporary 必须改,filesort 立即办;
覆盖索引最理想,Using index 放心赞。

写在最后

EXPLAIN 是 MySQL 性能优化的入场券。掌握它,你就能在索引设计、SQL 改写、架构选型上拥有判断力。

但 EXPLAIN 不是万能的:

  • 它是估算,不是精确值

  • 不统计存储引擎外的消耗(网络、客户端)

  • 不反映锁等待、CPU 开销

因此,EXPLAIN + 慢查询日志 + 性能监控,才是完整的 MySQL 调优体系。

相关推荐
2501_915921432 小时前
Fastlane 结合 AppUploader 来实现 CI 集成自动化上架
android·运维·ci/cd·小程序·uni-app·自动化·iphone
贤泽2 小时前
Android 15 AOSP Notification分析
android
木子02042 小时前
sql 计算年龄
数据库·sql
Coder_Boy_2 小时前
【Java核心】企业级高并发系统底层设计思想
java·前端·数据库·spring boot·高并发
知识即是力量ol3 小时前
口语八股:Redis 面试实战指南——基础篇、持久化篇
数据库·redis·面试·八股
特立独行的猫a3 小时前
腾讯Kuikly多端框架(KMP)实战:轮播图的完整实现
android·harmonyos·轮播图·jetpack compose·kuikly
学到头秃的suhian3 小时前
Redis的Java客户端
java·数据库·redis
yueyin1234563 小时前
在Django中安装、配置、使用CKEditor5,并将CKEditor5录入的文章展现出来,实现一个简单博客网站的功能
数据库·django·sqlite
人间打气筒(Ada)3 小时前
SQL Server 之创建和管理数据表
运维·服务器·数据库·windows·sql语句·sql server·windows server