MySQL Explain 返回列详解:从入门到实战,附 SQL 与避坑大全

本文基于 MySQL 5.7+ 和 8.0+ 版本梳理,适用于大多数 MySQL 版本。建议收藏,方便日后 SQL 优化查阅。

一、Explain 是什么?

Explain ​ 是 MySQL 提供的查询执行计划分析工具 。它通过模拟优化器的执行过程,告诉你一条 SQL 语句将如何读取数据、是否使用索引、扫描多少行等关键信息,是 SQL 性能优化的"透视镜"。

核心作用

  1. 查看表的读取顺序:了解多表关联时谁先谁后。

  2. 判断索引使用情况:确认是否走索引,避免全表扫描。

  3. 预估查询成本 :通过 rows字段估算扫描行数,定位性能瓶颈。

  4. 识别额外操作 :发现 Using filesort(文件排序)、Using temporary(临时表)等性能杀手。

二、Explain 用法与语法

1. 基础用法(最常用)

直接在 SQL 语句前加上 EXPLAIN即可。

复制代码
-- 分析单表查询
EXPLAIN SELECT * FROM user WHERE age > 18;

-- 分析多表连接
EXPLAIN SELECT u.name, o.amount 
FROM user u 
JOIN orders o ON u.id = o.user_id 
WHERE u.city = 'Beijing';

2. 进阶用法(MySQL 8.0+)

MySQL 8.0 提供了更强大的分析能力。

复制代码
-- 1. 实际执行并分析(显示实际耗时,MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT * FROM user WHERE age = 25;

-- 2. JSON 格式输出(包含更详细的成本模型数据)
EXPLAIN FORMAT=JSON SELECT * FROM user WHERE age = 25;

三、Explain 返回列详解(核心)

执行 EXPLAIN后,你会看到一张包含约 12 列的结果表。以下是每列的核心解读实战关注点

列名 含义 核心关注点
id 查询序列号 判断执行顺序(id 越大越先执行)
select_type 查询类型 区分简单查询、子查询、UNION
table 访问的表名 当前行数据属于哪张表
partitions 匹配的分区 若为分区表,显示命中的分区
type 访问类型 性能关键!(如 const, ref, ALL)
possible_keys 可能使用的索引 优化器理论可选的索引
key 实际使用的索引 实际走的索引(NULL 表示未走索引)
key_len 索引长度 判断联合索引中实际使用了多少列
ref 索引引用 显示与索引比较的列或常量
rows 预估扫描行数 越小越好,是估算值
filtered 过滤百分比 表示条件过滤后剩余数据的比例
Extra 额外信息 性能优化的关键提示(如 Using index)

四、核心列深度解析(附 SQL 示例)

1. type列:访问类型(性能核心)

type表示 MySQL 如何查找表中的行,性能从优到劣排序如下:

类型 含义 示例 SQL(假设有索引)
system 表只有一行(系统表) SELECT * FROM mysql.time_zone WHERE ...
const 最优,通过主键/唯一索引一次找到 SELECT * FROM user WHERE id = 1
eq_ref 多表 JOIN 时,被驱动表使用主键/唯一索引 SELECT * FROM a JOIN b ON a.id = b.idb.id 是主键)
ref 常见,使用普通索引等值匹配(可能多行) SELECT * FROM user WHERE age = 25(age 有索引)
range 索引范围扫描(BETWEEN, IN, >, <) SELECT * FROM user WHERE age > 20
index 全索引扫描(遍历索引树) SELECT age FROM user(age 有索引)
ALL 全表扫描(性能最差,需优化) SELECT * FROM user WHERE name = 'John'(name 无索引)

优化建议 :生产环境至少应达到 range级别,尽量避免 ALL(全表扫描)。

2. keypossible_keys:索引使用

  • possible_keys :理论上可能用到的索引(仅供参考)。

  • key实际使用的索引。

常见问题分析

  • key为 NULL:说明未使用索引,需检查查询条件或建索引。

  • possible_keys有值但 key为 NULL:通常因为数据量小或索引区分度低,优化器认为全表扫描更快。

3. Extra列:额外信息(优化关键)

Extra列提供了极其重要的性能线索

含义 优化建议
Using index 覆盖索引(极佳) 查询列全在索引中,无需回表。
Using where 使用 WHERE 过滤 正常情况,表示在存储引擎层或 Server 层进行了过滤。
Using filesort 文件排序(需优化) 无法利用索引排序,需额外排序操作。考虑为 ORDER BY字段加索引。
Using temporary 临时表(需优化) 常见于 GROUP BYDISTINCT操作。需为分组字段加索引。
Using join buffer 使用连接缓存 连接条件未使用索引,导致使用内存缓存。

4. rowsfiltered:扫描成本

  • rows :MySQL 预估需要扫描的行数(估算值 ,非精确值)。越小越好

  • filtered :表示经过 WHERE条件过滤后,剩余行数的百分比。rows * filtered可估算连接查询中下一张表需要处理的行数。

五、实战案例:SQL 优化前后对比

场景:无索引导致全表扫描(type=ALL

问题 SQL

复制代码
EXPLAIN SELECT * FROM orders WHERE user_id = 100;

执行计划分析

id type key rows Extra
1 ALL NULL 10000 Using where

诊断type=ALL表示全表扫描,key=NULL表示未使用索引,rows=10000表示扫描了 1 万行,性能极差。

优化方案 :为 user_id添加索引。

复制代码
CREATE INDEX idx_user_id ON orders(user_id);

优化后执行计划

id type key rows Extra
1 ref idx_user_id 1 Using index

优化效果typeALL提升为 ref(索引等值匹配),rows从 10000 降为 1,性能提升千倍。

六、总结:Explain 分析 checklist

  1. type :是否出现 ALL(全表扫描)?必须优化。

  2. key :是否实际使用了索引?key不应为 NULL。

  3. Extra :是否出现 Using filesortUsing temporary?这两个是性能杀手,需通过调整索引或 SQL 写法消除。

  4. rows:预估扫描行数是否过大?过大说明索引可能失效或缺失。

版权声明:本文为 CSDN 博主原创,转载请注明出处。如有疑问,欢迎评论区交流。

参考来源:MySQL 官方文档、腾讯云开发者社区、脚本之家等。

相关推荐
CYRUS_STUDIO10 小时前
Frida 检测与对抗实战:进程、maps、线程、符号全特征清除
android·逆向
csj5011 小时前
安卓基础之《(28)—Service组件》
android
lhbian13 小时前
PHP、C++和C语言对比:哪个更适合你?
android·数据库·spring boot·mysql·kafka
catoop14 小时前
Android 最佳实践、分层架构与全流程解析(2025)
android
ZHANG13HAO15 小时前
Android 13 特权应用(Android Studio 开发)调用 AOSP 隐藏 API 完整教程
android·ide·android studio
田梓燊15 小时前
leetcode 142
android·java·leetcode
angerdream15 小时前
Android手把手编写儿童手机远程监控App之JAVA基础
android
菠萝地亚狂想曲16 小时前
Zephyr_01, environment
android·java·javascript
sTone8737516 小时前
跨端框架通信机制全解析:从 URL Schema 到 JSI 到 Platform Channel
android·前端