小易说IT 小易说IT

MySQL 慢查询日志完整分析指南

慢查询日志本质:MySQL 把执行超过阈值、或未走索引的 SQL,按顺序记录到日志文件 /mysql.slow_log表里。 核心目标:找到热点 SQL、区分是真的执行慢,还是锁等待、扫描行数巨大。

前置:先确认配置

show variables like 'slow_query_log_file'; -- 日志文件路径
show variables like 'long_query_time';    -- 阈值(秒)
show variables like 'log_queries_not_using_indexes'; -- 记录无索引SQL
show variables like 'log_output';         -- FILE / TABLE

一、慢日志原始字段含义(文本格式)

一条典型慢日志片段示例:

# Time: 2026-10-28T14:20:01.123456+08:00
# User@Host: app[app] @  [127.0.0.1]  Id: 12345
# Query_time: 2.123456  Lock_time: 0.000100 Rows_sent: 10  Rows_examined: 250000
SET timestamp=1761632401;
select * from t_order where user_id=10086;

重点 4 个指标(重中之重)

  1. Query_time:SQL 从开始到结束总耗时(包含等待锁时间!!很多人踩坑)

  2. Lock_time:等待行锁 / 表锁消耗的时间

    • Lock_time 高:不是 SQL 本身慢,被其他事务阻塞,优先查长事务、锁等待

    • Lock_time 很小,但 Query_time 很大:是 SQL 本身执行慢(扫描数据多、缺少索引、排序)

  3. Rows_sent:返回给客户端行数

  4. Rows_examined:MySQL扫描读取的行数 ✅ 核心判断:Rows_examined >> Rows_sent,说明扫描大量无效数据,典型索引缺失、索引失效。

口诀: Lock_time 高 → 查锁、长事务 Lock_time 低,但 Query_time 高、Rows_examined 巨大 → 索引 / SQL 写法问题

其他字段:

  • User@Host:来源账号和 IP,定位哪个服务

  • Id:线程 ID,对应 show processlist 的 ID

  • SET timestamp:SQL 执行时间戳

二、工具 1:mysqldumpslow(官方自带,最常用)

作用:合并相同指纹 SQL、聚合统计,避免一条条看原始日志。 语法:

mysqldumpslow [参数] 慢日志文件路径

常用参数

  • -s:排序字段

    • t:总耗时(sum Query_time,优先看这个,找最耗资源的热点)

    • at:平均耗时

    • c:执行次数(高频 SQL,即使单次不快,累计压力大)

    • r:返回行数

    • ar:平均返回行数

    • l:锁时间

  • -t N:只输出 TOP N 条

  • -g "正则":过滤 SQL,如 -g "select" / -g "update"

  • -a:不抽象数字、字符串(默认会把值替换成 S、N,看不到真实值)

常用命令模板

# 1. 按总耗时TOP10(优先)
mysqldumpslow -s t -t 10 /var/lib/mysql/localhost-slow.log

# 2. 按执行次数TOP20(高频小慢SQL,压垮DB)
mysqldumpslow -s c -t 20 /var/lib/mysql/localhost-slow.log

# 3. 只看select语句,平均耗时排序
mysqldumpslow -s at -g "select" -t 15 /var/lib/mysql/localhost-slow.log

# 4. 显示真实参数,不抽象
mysqldumpslow -s t -a -t 10 /var/lib/mysql/localhost-slow.log

输出解读示例:

Count: 80  Time=1.20s (96s)  Lock=0.00s (0s)  Rows=10.0 (800), app[app]@127.0.0.1
  SELECT * FROM t_order WHERE user_id = N
  • Count:执行 80 次

  • Time:单次平均 1.2s,累计 96s

  • Lock:几乎无锁等待,确定是 SQL 本身慢

  • Rows:每次返回 10 行,总共返回 800 行,结合原始日志看 examined 行数

⚠️ 缺点:mysqldumpslow不展示 Rows_examined,想看扫描行数,要么看原始日志、要么用 pt-query-digest

三、工具 2:pt-query-digest(Percona Toolkit,生产首选,强烈推荐)

比 mysqldumpslow 强很多:自带 Rows_examined 统计、占比、直方图、输出报告,线上慢日志分析标准工具。

# 基础分析
pt-query-digest /var/lib/mysql/localhost-slow.log

# 只分析最近1小时的慢日志
pt-query-digest --since '1h ago' /var/lib/mysql/localhost-slow.log

# 过滤select
pt-query-digest --filter '$event->{fingerprint} =~ m/select/i' /var/lib/mysql/localhost-slow.log

报告 3 大块:

  1. 全局统计:总查询数、总耗时、95 分位耗时

  2. 热点 SQL 排名(按总耗时占比,重点看 %)

  3. 单条详情:包含 Query_time / Lock_time / Rows_examined / Rows_sent / 执行时间分布

重点看 Rows_examined,评估扫描效率。

四、工具 3:直接查表模式 log_output=TABLE

日志存在 mysql.slow_log,适合不方便拿日志文件、云数据库(很多云 DB 不给日志文件,只能查表)

SELECT
  start_time,
  query_time,
  lock_time,
  rows_sent,
  rows_examined,
  db,
  user_host,
  sql_text
FROM mysql.slow_log
WHERE start_time >= NOW() - INTERVAL 1 HOUR
ORDER BY query_time DESC
LIMIT 100;

可以自己写 SQL 做聚合(按 SQL 指纹分组统计)

五、标准分析步骤(固定流程,直接落地)

拿到慢日志后,按这个顺序排查,避免瞎优化索引

  1. 筛选时间段:优先故障时段日志

  2. 聚合统计:用 pt-query-digest /mysqldumpslow 抓 TOP 热点 SQL

    区分两类慢 SQL:

    • 低频、单次极慢(比如报表、大查询)

    • 高频、单次几百 ms,执行几万次(最容易打垮数据库)

  3. 看 Lock_time

    • Lock_time 高:停止索引优化,转向排查长事务、锁等待、gap 锁

    • Lock_time 低:继续分析 SQL 本身

  4. 对比 Rows_examined 和 Rows_sent

    • examined ≈ sent ✅:效率不错,可能只是数据量大、排序分组

    • examined >> sent ❌:大概率索引缺失、索引失效、过滤条件写的不好

  5. 拿 SQL 执行 EXPLAIN 复制 SQL,explain 看执行计划:type、key、Extra(Using filesort/temporary)

  6. 验证优化效果:上线后持续观察该 SQL 在慢日志里是否消失

六、典型慢日志案例判断

案例 1

Query_time: 3.0  Lock_time: 2.8 Rows_sent: 1 Rows_examined:1

✅ 判断:锁等待,SQL 本身扫描 1 行很快,等锁等了 2.8s,去查 innodb_lock_waits、长事务。

案例 2

Query_time: 2.5 Lock_time:0.001 Rows_sent:5 Rows_examined:400000

✅ 判断:索引失效 / 缺少索引,扫描 40w 行只返回 5 条,优先加索引、改写条件。

案例 3

Query_time:1.8 Lock_time:0.002 Rows_sent:30000 Rows_examined:32000

✅ 判断:查询本身就要读出大量数据(导出、报表),不是索引问题,考虑异步、OLAP、分页、限制返回。

七、常见坑

  1. long_query_time 是 SQL 执行完成后才记录:正在跑的 SQL 不会进慢日志,正在执行的 SQL 要用show processlist /performance_schema 抓

  2. log_queries_not_using_indexes 开启后,小表全扫描也会刷大量日志,淹没真正慢 SQL,线上不建议长期开启

  3. 慢日志里的 Query_time 包含网络等待、锁等待,不等于 CPU 执行时间

  4. mysqldumpslow 默认把参数抽象成 N / S,看不到真实值,排查问题时加 -a

  5. 云 MySQL(阿里云 RDS、腾讯云 CDB)一般支持控制台直接看慢查询分析,底层也是这套逻辑

八、排查优先级总结

锁等待(Lock_time 高) > 扫描行数巨大(examined 超大) > 文件排序 / 临时表 > 高频小慢查询 > 离线报表类大查询


本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。

原文链接 https://www.yijunzhao.cc/archives/mysql-slow-query-log-complete-analysis-guide

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/