【MySQL百日打怪升级第23天】慢查询日志分析 —— 网站慢了,第一步该看什么?

简介: 本文是DBA老兵分享的慢查询日志分析实战指南:从配置启用(slow_query_log、long_query_time等)、日志解读(重点看Rows_examined/Rows_sent比值)、工具选用(pt-query-digest为首选)到完整排查流程,强调“先看日志再动手”,避免盲目重启加缓存。含避坑提示与面试考点。

慢查询日志分析 —— 网站慢了,第一步该看什么?


大家好,我是一名拥有10年以上经验的DBA老兵。

做这个系列,源于一个朴素的愿望:把踩过的坑、总结的经验系统化输出,希望能帮到刚入行或想进阶的兄弟们。

让我们开始今天的第23天内容。


前两天聊了死锁,今天聊一个更常见的场景——网站突然变慢了。

这时候大多数人的反应是:重启、加缓存、加机器。但一个合格的 DBA 第一件事是——查慢查询日志。

慢查询日志是 MySQL 给你留的"案发现场"。谁慢了?慢在哪里?花了多久?全记在上面。不看日志就动手,属于闭着眼睛修车。


配置:先确保日志开着

很多服务器的慢查询日志默认是关的。第一步确认它开着:

SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

关键参数:

参数 说明 推荐值
slow_query_log 是否开启 ON
slow_query_log_file 日志文件路径 默认在 data 目录
long_query_time 超过多少秒算慢 线上 12,分析时临时设 0
log_queries_not_using_indexes 没走索引的查询也记录 非生产和低负载:ON;高负载生产:酌情开
log_slow_admin_statements 慢管理语句也记录(DDL等) 建议 ON

长期建议 long_query_time=1,意思是超过 1 秒就算慢。有些团队设 0.5,也可以,但要看你服务器的负载——如果日志量太大,设太短反而淹没了真正的慢查询。

log_queries_not_using_indexes 也要注意代价:如果业务代码里有大量没走索引的小查询,这个开关一开会让你的日志文件瞬间暴涨,IO 开销也跟着上来。

⚠️ 注意:在高并发生产环境开启 log_queries_not_using_indexes 前,先评估你的慢查询量。如果业务代码里大量查询都没走索引(哪怕单次只要几十毫秒),这个开关会让日志量暴增 10-100 倍,IO 也会跟着涨。建议先在从库或低峰期试开,观察一段时间再决定是否长期开启。

一句话总结:非生产环境必开,低负载生产建议开,高并发生产开在从库上或只在排查时临时开。

临时调成 0 抓全量是个好技巧:

SET GLOBAL long_query_time = 0;
-- 跑一段时间抓完,记得改回来
SET GLOBAL long_query_time = 1;

但有个风险:如果你忘了改回来,日志会把磁盘撑爆。 建议要么设个定时任务自动恢复:

# 10 分钟后自动恢复
echo "SET GLOBAL long_query_time = 1;" | mysql -u root -p

要么不用 0,设一个极低但安全的值:

SET GLOBAL long_query_time = 0.01;  -- 10 毫秒,过滤掉真正的零耗时查询

注意 SET GLOBAL 对已有连接不生效,新连接才生效。

还有一件事容易被忽略:慢查询日志是同步写操作。 MySQL 每执行完一条符合条件的慢查询,必须把日志写进磁盘才继续往下走。所以日志 IO 本身也会影响性能——如果日志盘 IO 撑满了,查询也会被拖慢。

因此日志文件要定期切割。切割时慢日志和全日志一起做,用 move 方式切换,不要直接 truncate

# 凌晨低峰期,写个脚本统一切割
mv /var/log/mysql/slow.log /var/log/mysql/slow.log.$(date +%Y%m%d)
mv /var/log/mysql/general.log /var/log/mysql/general.log.$(date +%Y%m%d)
mysqladmin -u root -p flush-logs

为什么用 mv + flush-logs 而不是直接 truncate?

  • mv 只是改了文件名,MySQL 进程打开的文件描述符依然指向同一个 inode,所以在 flush 之前,日志会继续写入已被改名的旧文件,不会丢失。
  • 执行 flush-logs 后,MySQL 关闭旧文件句柄、创建新文件。切换过程有极短暂的阻塞窗口,但选在凌晨低峰期做,影响几乎可以忽略。
  • 千万不要 cat /dev/null > slow.log 或直接 rm 正在写的日志文件

logrotate 配好 postrotate 脚本也能自动完成切割。


读一条慢查询日志

一条典型的慢查询日志长这样:

# Time: 2026-05-18T10:30:15.123456Z
# User@Host: app_user[app_user] @ db01.example.com [10.0.1.100]  Id: 12345
# Query_time: 12.345678  Lock_time: 0.001234  Rows_sent: 10  Rows_examined: 500000
SET timestamp=1747559415;
SELECT o.id, o.amount, u.name
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending'
ORDER BY o.created_at DESC
LIMIT 10;

每一列都有用:

字段 含义 重点关注
Query_time SQL 执行耗时(秒) 是否超过 long_query_time
Lock_time 锁等待时间 如果锁时间占比高,可能是锁竞争
Rows_sent 最终返回的行数 正常
Rows_examined 扫描了多少行 核心指标 —— Rows_examined 远大于 Rows_sent 说明扫描了大量数据

上面这个例子:扫描了 50 万行,只返回了 10 行。 50万/10 的比值过于离谱,一眼就可以判断——o.status 没有索引,或者有索引但选择性太差了。


工具:不要手动翻日志

日志文件大了以后(线上经常几 GB),不要 cat 看,用工具。

mysqldumpslow(MySQL 自带)

# 按平均查询时间排序,看前 10 条
mysqldumpslow -t 10 /var/log/mysql/slow.log

# 按执行次数排序
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

自带工具的好处是哪里都有,不用额外安装。缺点是分析能力有限,只能做简单的聚合。

pt-query-digest(Percona Toolkit)

这是 DBA 的标配。如果只能装一个 MySQL 工具,我选这个。

# 分析慢查询日志,输出一份完整的报告
pt-query-digest /var/log/mysql/slow.log

# 输出到文件慢慢看
pt-query-digest /var/log/mysql/slow.log > slow_report.txt

pt-query-digest 会输出一份按"总耗时"排序的报告,告诉你哪些 SQL 消耗了最多的数据库时间。排名第一的那个,就是你要优化的头号目标。

举个例子,它的输出会告诉你:

# Rank Query ID           Response time    Calls  R/Call  V/M   Item
# ==== ================== ================ ====== ======= ===== ====
# 1    0xAB12CD34EF56...   1256.3456 45.2%  1234   1.0178  0.03  SELECT orders
# 2    0xCD78EF90AB12...    456.7890 16.4%   567   0.8056  0.10  SELECT users

第1条 SQL 占了 45% 的慢查询总时间。优化它就解决了一半问题。

如果需要自动化集成(比如定时分析、对接告警系统),pt-query-digest 支持 JSON 输出:

pt-query-digest --output json /var/log/mysql/slow.log > slow.json

JSON 格式按 query 类分组,每条包含 fingerprint、metrics(Query_time、Rows_examined 等)、样本 SQL。配合 jq 处理非常方便,比如提取总耗时排名前5的 SQL:

pt-query-digest --output json slow.log | jq '.classes[:5] | .[].sample'

也有 --output json-anon 模式,会去掉样本 SQL 中的具体数据,适合脱敏后传给第三方分析。


一个完整的分步流程

我处理线上慢查询的步骤:

第一步:确认到底有多慢

-- 看一眼当前正在跑的查询
SHOW FULL PROCESSLIST;
-- 看 Time 列:跑了多久了?

第二步:打开慢查询日志,确认是偶发还是持续

tail -100 /var/log/mysql/slow.log

第 2.5 步:看一眼系统负载(容易被跳过但很重要)

top -bn1 | head -5      # CPU 负载
iostat -x 1 3           # 磁盘 IO 是否打满
free -h                 # 内存是否吃紧

如果 CPU/IO 已经打满,慢查询可能只是"受害者"。先找到真正的资源杀手(通常也是没走索引的全表扫描),别揪着某条 SQL 死磕。

第三步:用 pt-query-digest 找到头号敌人

pt-query-digest /var/log/mysql/slow.log | head -80

第四步:对目标 SQL 做 EXPLAIN

EXPLAIN SELECT ...\G

第五步:做索引优化或 SQL 改写,验证效果


⚠️ 一个常见的误判:慢的不一定是它自己

慢查询日志告诉你"这条 SQL 花了 10 秒",但原因不一定在这条 SQL 本身

有种常见的场景:这条 SQL 单独拿出来跑只要 100 毫秒,但在线上就是 10 秒。为什么?因为当时系统里还有其他慢查询在吃资源——CPU 打满了、IO 带宽被占完了、内存被挤爆了。

这条 SQL 本身没有变慢,它是被挤慢的。就像是堵车——不是你的车有问题,是整个路口都堵死了。

怎么判断?

-- 看当时系统的负载状态(如果日志里有)
# Schema: db1  # 数据库名
# Query_time: 10.5  Lock_time: 0.001  # SQL 耗时 10 秒

-- 如果同时间段有大量其他慢查询,且这条 SQL 单独 EXPLAIN 走索引、
-- rows 扫描量很小——大概率是被"挤慢"的,不是它自己的锅

取出来单独跑一下就能验证:

# 把这条 SQL 粘出来,在数据库里跑一次
# 如果单独跑很快,回去查同时间段的系统负载

根因可能是:其他全表扫描的 SQL 吃光了 IO、某个定时任务占满了 CPU、备份脚本在跑。这种情况你的优化目标不是这条 SQL,而是把那个真正的"资源杀手"找出来

所以诊断慢查询时,别只盯着"最慢的"那一两条。结合 SHOW FULL PROCESSLIST 和系统负载(CPU、IO、内存)一起看,才能找到真正的根因。


慢查询日志分析用 AI 有个常见的误区——把整份日志文件丢给 AI。 如果日志几 MB 甚至几百 MB,Token 消耗是天文数字,AI 光读完就超时了。

正确姿势:先用传统工具做聚合,再把样本交给 AI 做深度分析。

正确流程

慢查询日志(.log)
       ↓
pt-query-digest --output json(聚合排序,输出 JSON)
       ↓
从 JSON 中提取排名靠前的 SQL 样本(结构化,Token 极省)
       ↓
用 AI 执行 EXPLAIN 分析索引使用情况
       ↓
结合索引优化知识给出改索引或改 SQL 的建议

实操:从 pt-query-digest JSON 到 AI 分析

用 JSON 格式输出,比文本报告更适合 AI 处理——结构清晰、没有无关字符、Token 省很多:

pt-query-digest --output json /var/log/mysql/slow.log > slow.json

然后用 jq 提取排名靠前的样本 SQL 和关键指标:

# 提取前 5 条慢查询的样本 SQL 和执行次数
jq '.classes[:5] | .[] | {sql: .sample, calls: .metrics.Query_time.cnt, total_time: .metrics.Query_time.sum}' slow.json

把这条命令的输出直接交给 AI:

帮我分析这条 SQL 为什么慢,建议创建什么索引:

SELECT o.id, o.amount, u.name
FROM orders o JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending'
ORDER BY o.created_at DESC LIMIT 10;

先执行 EXPLAIN,结合输出分析索引使用情况。

如果 AI 工具支持 MCP 直连数据库(比如 OpenCode 连接了数据库 MCP),可以让 AI 直接跑 EXPLAIN

执行 EXPLAIN SELECT ...,看 type、key、rows、Extra 字段,判断有没有走索引,给出优化建议。

结合前面 Day 5-6 讲的索引原理和 Day 24 即将讲的 EXPLAIN 解读,AI 可以帮你把一条慢查询从"知道慢"推进到"知道为什么慢、怎么修"。


面试加餐

Q: long_query_time 设为 0 会有什么后果?

会记录所有查询。这在排查问题时很有用(临时开启),但生产环境不要长期设为 0。MySQL 写日志是有 IO 开销的,所有查询都记会导致日志疯长,甚至把磁盘写满。用完记得关。

Q: Rows_examined 很大但 Rows_sent 很小,一定有问题吗?

不绝对。SELECT COUNT(*) FROM big_table 即使有索引也扫描了全表,但 Rows_sent = 1,这是正常的。但如果是一个 OLTP 查询(比如按用户查订单),Rows_examined 远大于 Rows_sent,基本可以判断索引有问题。

Q: pt-query-digest 和 mysqldumpslow 哪个好?

pt-query-digest 强太多了。它不仅按总耗时排序,还能做指纹聚合(把 WHERE id = ? 参数化后归并)、按时间段分析趋势、输出各种维度的统计。mysqldumpslow 就是 MySQL 自带的"能看就行"的版本。pt-query-digest 是 DBA 工具箱里最常用的工具,没有之一。


总结

🎯 面试考点

  • 慢查询日志的配置slow_query_log=ONlong_query_timelog_queries_not_using_indexes
  • 日志关键字段:Query_time、Lock_time、Rows_examined、Rows_sent —— 核心看扫描/返回比值
  • 分析工具mysqldumpslow(自带基本版)、pt-query-digest(DBA 标配)
  • 排查流程:SHOW PROCESSLIST → 查慢日志 → pt-query-digest 聚合 → EXPLAIN 定位 → 加索引 / 改 SQL
  • Rows_examined >> Rows_sent 是索引缺失的典型信号

今天就试一下:登录你的数据库,跑这条 SQL:

SHOW VARIABLES LIKE 'slow_query%';

看一眼你的慢查询日志开了没有。如果没开——今天就把它打开。

SET GLOBAL slow_query_log = ON;
SET GLOBAL log_queries_not_using_indexes = ON;

下期预告:EXPLAIN 执行计划解读 —— 面试必问!


有问题欢迎评论区交流,明天见!

相关文章
|
11天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3294 10
|
3天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
1656 5
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
14天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3347 24
|
7天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2385 4
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
26天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23599 15
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
|
13天前
|
人工智能 JSON BI
DeepSeek V4-Pro 接入 Claude Code 完全实战:体验、测试与关键避坑指南
Claude Code 作为当前主流的 AI 编程辅助工具,凭借强大的代码理解、工程执行与自动化能力深受开发者喜爱,但原生模型的使用成本相对较高。为了在保持能力的同时进一步降低开销,不少开发者开始寻找兼容度高、价格更友好的替代模型。DeepSeek V4 系列的发布带来了新的选择,该系列包含 V4-Pro 与 V4-Flash 两款模型,并提供了与 Anthropic 完全兼容的 API 接口,理论上只需简单修改配置,即可让 Claude Code 无缝切换为 DeepSeek 引擎。
2870 3
|
5天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全+三种模式+记忆体系+实战工作流完整手册
Claude Code 是当前最流行的终端级 AI 编程助手,能够直接在命令行中完成代码生成、项目理解、文件修改、命令执行、错误修复等全流程开发工作。它不依赖图形界面、不占用额外资源,却能深度理解项目结构,自动生成规范代码,大幅提升研发效率。
953 2
|
12天前
|
存储 Linux iOS开发
【2026最新】MarkText中文版Markdown编辑器使用图解(附安装包)
MarkText是一款免费开源、跨平台的Markdown编辑器,主打所见即所得实时预览,支持Windows/macOS/Linux。内置数学公式、流程图、代码高亮、多主题及PDF/HTML导出,是Typora的轻量免费替代首选。(239字)

热门文章

最新文章