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

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

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

一、先找到慢 SQL 在哪

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

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

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

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全表扫描,性能杀手。数据量大时一定要想办法优化掉。

一条经验法则:单表查询的 typeALL,几乎必然有问题;是 refconst,基本 OK。

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

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

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

其中 Using filesortUsing 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=refkey=idx_citycity 走索引了,等值匹配没问题。
  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 filesortUsing temporary,用联合索引消除它们。

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

相关推荐
Logintern092 小时前
PostgreSQL 的 ORDER BY 多列排序
数据库·postgresql
今天AI了吗3 小时前
DeepSeek Harness 深度解析:从评测架构到实战落地
java·网络·数据库·人工智能·架构·java-ee
数据库小学妹3 小时前
为什么MySQL索引用B+树?从存储底层讲透原理
数据库·mysql·b+树·索引优化·磁盘io·数据库原理
BestHeaker3 小时前
制造业 MES 开发入门:和互联网业务开发的 5 个本质差异(一)
数据库·经验分享·制造业·mes
自动化监测Learner4 小时前
Navicat Premium 17 中文版安装教程(2026最新版)
java·linux·数据库
张文是假的啊5 小时前
常用JPA注解解释
数据库
Allen_LVyingbo6 小时前
医疗AI基础2026-构建可靠智能体的编程路径(上)
大数据·数据库·人工智能·python·自动化
疯狂打码的少年6 小时前
【数据库技术】多值依赖与第四范式(4NF)
数据库·笔记·算法