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.id(b.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. key与 possible_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 BY、DISTINCT操作。需为分组字段加索引。
Using join buffer​ 使用连接缓存 连接条件未使用索引,导致使用内存缓存。

4. rows与 filtered:扫描成本

  • 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

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

六、总结:Explain 分析 checklist

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

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

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

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

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

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

相关推荐
其实防守也摸鱼1 天前
Fastjson 反序列化漏洞(JNDI注入)
android·数据库·安全·oracle·自动化·fastjson·反序列化
狗凯之家源码网1 天前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
消失的旧时光-19431 天前
(第一篇)JNI 多线程到底难在哪:从 Linux Thread 到 JNIEnv
android·jni·ndk
逗脑IDE1 天前
零基础学ESP32:蓝牙控制舵机——手机一点,舵机就转!
android·智能手机
清霜之辰1 天前
骁龙 8397 舱驾融合平台端侧大模型部署:7B 模型本地推理与 64GB 内存账本
android
烽火聊员1 天前
Android屏幕卡顿traces.txt拉取查看
android·java·android studio
只睡四小时2 天前
JS 手写 D-pad 空间导航:电视端焦点引擎实战
android·开发语言·前端·javascript·ecmascript·hls·空间导航
恋猫de小郭2 天前
Android 原生的 Compose A2UI 也来了,你还抱着 XML 养老吗?
android·前端·flutter
程序媛_2 天前
【JMeter】准备token文件
android·jmeter
维克兜率天2 天前
【维克】弹性策略:用“乖离率“捕捉超跌反弹
android·开发语言·python·深度学习·kotlin·量化