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

相关推荐
wno7041 小时前
postgresSQL压缩版安装与基本命令
数据库·postgresql
聚美智数3 小时前
智能结构化识别-图片结构解析-图像结构化解析-照片结构化解析
android·java·数据库
瀚高PG实验室3 小时前
瀚高数据库常用系统表查询入门指南(附常用SQL)
数据库·sql·postgresql·瀚高数据库
ben9518chen4 小时前
mysql数据库基本操作
数据库·mysql
2603_965148114 小时前
电商选品调研:通过关键词搜索API获取市场热销商品,结合商品详情API分析竞品卖点与定价
开发语言·数据库·人工智能·python·信息可视化
土豆.exe4 小时前
nf_tables 的 verdict 被读了两次:一个十年未闭合的位域错配
java·数据库·网络安全·缓存
缓慢更新5 小时前
表单引擎的存储建模:宽表与文档库的取舍
运维·服务器·网络·数据库·低代码·oracle·适配器模式
Web3&Basketball6 小时前
实测Gemini4Argon:ERQA 87%登顶长程任务榜
数据库·python·大模型·多模态·gemini·长上下文·推理优化
xiaogai_gai7 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
注塑机数据采集联网7 小时前
注塑机数据采集网关对接MES系统数字化技术方案
大数据·网络·数据库·物联网·数据挖掘·数据分析