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 输出格式一节。

相关推荐
小白男神5 天前
MySQL进阶学习四(存储过程、游标、触发器)
mysql
这个DBA有点耶5 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
DBA_G5 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库
自由能燃气设备5 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
科创致远5 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
kybs19915 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
2601_962218615 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法
程序猿_极客5 天前
【免费】分享一套优质的基于SSM的校园失物招领系统的设计与实现,源码+文档+视频详解(讲解)
java·mysql·ssm·课程设计·失物招领系统
张洛闻Eren5 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
于平安5 天前
MySQL-触发器
数据库·mysql