MySQL 慢查询排查实战:EXPLAIN 看懂 type 与 Extra,一个字段定位性能问题

MySQL 慢查询排查实战:EXPLAIN 看懂 type 与 Extra,一个字段定位性能问题

数据库变慢往往不是数据库本身"不行了",而是某条 SQL 走错了执行计划。本篇面向刚接触 MySQL 的开发者,手把手讲清楚怎么用 EXPLAIN 定位慢查询,重点解释 type 和 Extra 两个最容易读不懂的字段。读完你可以直接拿自己项目的慢 SQL 上手排查。

一、先找到慢 SQL 在哪

优化之前得先知道哪些 SQL 慢。MySQL 自带慢查询日志,默认可能没开。先确认:

sql 复制代码
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';

如果 slow_query_log 是 OFF,可以临时打开(重启后失效,正式环境请写入配置文件):

sql 复制代码
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;   -- 超过 1 秒的查询记日志

更推荐用另一条动态视图:information_schema.PROCESSLIST 里能直接看到正在执行、耗时长的语句:

sql 复制代码
SELECT * FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Query' AND TIME > 1;

拿到慢 SQL 后,下一步就是用 EXPLAIN 分析它为什么慢。

二、EXPLAIN 到底看什么

给任意 SELECT、UPDATE、DELETE 前面加 EXPLAIN,就能看到它打算怎么执行:

sql 复制代码
EXPLAIN SELECT * FROM users WHERE email = 'demo@example.com';

输出是一张表,列比较多,初次看会懵。真正决定性能的核心列只有三个:type(访问类型)、key(实际用的索引)、Extra(附加信息)。下面逐个讲。

三、type:访问类型从好到坏

type 描述 MySQL 用什么方式找到记录,性能从好到坏大致是:

复制代码
system > const > eq_ref > ref > range > index > ALL

逐个说明:

  • const :主键或唯一索引的等值查询,最多命中一行。比如 WHERE id = 1。这是最快的结果之一。
  • eq_ref :联表查询时,对关联表的每一行,用主键/唯一索引正好命中一行。常见于 JOIN。
  • ref :用非唯一索引做等值匹配,可能命中多行。WHERE email = ? 且 email 有普通索引时通常是 ref。这是日常最健康的单表等值查询形态。
  • range :索引范围扫描,BETWEEN、>、<、IN 会触发。比全表快,但要看范围大小。
  • index:扫描整个索引树(不是全表,但也没省多少),比 ALL 略好。
  • ALL :全表扫描,性能杀手。数据量大时一定要想办法优化掉。

一条经验法则:单表查询的 type 是 ALL,几乎必然有问题;是 ref 或 const,基本 OK。

四、Extra:附加信息里的危险信号

Extra 里会写很多提示,其中几个要特别警惕:

Extra 内容 含义 处理方向
Using filesort 排序无法用索引完成,需要额外排序 给 ORDER BY 列建索引
Using temporary 用了临时表 检查 GROUP BY / DISTINCT 列是否有索引
Using index 覆盖索引,直接从索引拿数据 这是好事,性能佳
Using where 用 WHERE 过滤了索引扫描后的结果 正常,但配合 ALL 要留意

其中 Using filesort 和 Using temporary 是两块最常见的"隐藏性能税":它们意味着 MySQL 在内存里又排了一次序或建了一张临时表,数据量一大就会拖垮响应,甚至把临时表落到磁盘。

五、一个完整排查例子

假设有张用户表:

sql 复制代码
CREATE TABLE users (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(64) NOT NULL,
  city VARCHAR(32) NOT NULL,
  created_at DATETIME NOT NULL,
  INDEX idx_city (city)
);

业务里有条查询,按城市查最近注册的用户:

sql 复制代码
EXPLAIN SELECT * FROM users WHERE city = '北京' ORDER BY created_at DESC LIMIT 20;

你会看到类似结果:

复制代码
type: ref
key: idx_city
Extra: Using index condition; Using filesort

解读:

  1. type=ref,key=idx_city:city 走索引了,等值匹配没问题。
  2. Extra 里有 Using filesort :说明 ORDER BY created_at 没用到索引,MySQL 把命中的行再单独按 created_at 排了一次序。

如果 city = '北京' 命中几万行,这排序开销就很大。优化方法是建一个符合最左前缀的联合索引,让筛选和排序都走同一棵树:

sql 复制代码
ALTER TABLE users ADD INDEX idx_city_created (city, created_at);

再看:

复制代码
type: ref
key: idx_city_created
Extra: Using index condition

Using filesort 消失,排序直接顺着索引做,性能明显提升。

六、小结

EXPLAIN 是 MySQL 性能排查的第一利器,核心就三点:

  • 用慢查询日志或 PROCESSLIST 找到慢 SQL;
  • 看 type,发现 ALL 优先处理;
  • 看 Extra,警惕 Using filesort 和 Using temporary,用联合索引消除它们。

下一步建议:打开你自己的项目,抓一条你觉得慢的查询,跑一遍 EXPLAIN,确认它的 type 和 Extra,再决定要不要加索引或改写。更多字段含义可查官方手册里 EXPLAIN 输出格式一节。

相关推荐
许彰午8 小时前
01-Oracle数据库简介与版本选择
数据库·oracle
菜鸟~noob2339 小时前
【电子战】第三季预告—波武器与电子系统强力毁伤
开发语言·数据库·matlab·电子战
hasty10 小时前
policy.xml 在,不代表策略生效:ImageMagick 补丁给安全配置验收的提醒
xml·mysql·安全
Seraphina3610 小时前
SQL注入(二)盲注
网络·数据库·经验分享·笔记·sql
盟接之桥12 小时前
AI助手:你的7×24小时智能管家——让异常预警无处不在
大数据·网络·数据库·人工智能·制造·ai编程
waoooqwe12 小时前
问卷样本真实吗
大数据·数据库·算法·数据分析
可乐ea12 小时前
Agent 评测换判据:用终态数据库状态判定任务是否完成
数据库·ui·oracle·mcp工具·agent评测·终态断言·智能体可靠性
l1t12 小时前
DeepSeek总结的一个不含数据的 DuckDB 数据库
服务器·数据库·duckdb
PaperData13 小时前
2007-2020年税收调查面板数据
数据库
程序员清风14 小时前
CSV、Excel 与数据库数据读取实践
数据库·oracle·excel