4. 慢查询日志分析:开启慢查询日志、使用 mysqldumpslow / pt-query-digest 分析、定位慢 SQL
在高并发评分通道中,数据库性能瓶颈往往源于未被发现的慢查询。慢查询日志是 MySQL 提供的最基础、最直接的性能诊断工具。本章将系统讲解如何正确开启慢查询日志,以及如何利用 mysqldumpslow 和 pt-query-digest 两款工具高效定位慢 SQL。
4.1 慢查询日志的开启与配置
慢查询日志记录执行时间超过指定阈值(long_query_time)的 SQL 语句。在生产环境中,建议谨慎开启,避免日志文件过大导致磁盘 I/O 压力。
| 配置项 | 默认值 | 推荐值(高并发场景) | 说明 |
|---|---|---|---|
slow_query_log |
OFF | ON | 开启慢查询日志 |
slow_query_log_file |
主机名-slow.log | /var/log/mysql/slow-query.log | 日志文件路径 |
long_query_time |
10.000000 | 1.000000 或 0.500000 | 阈值(秒),评分通道建议 ≤1s |
log_queries_not_using_indexes |
OFF | ON | 记录未使用索引的查询 |
log_slow_admin_statements |
OFF | ON | 记录慢管理语句(ALTER、ANALYZE 等) |
min_examined_row_limit |
0 | 1000 | 扫描行数超过此值才记录(过滤小表全表扫描) |
配置示例(动态生效,无需重启):
SET GLOBAL slow_query_log = ON;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log';
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;
SET GLOBAL log_slow_admin_statements = ON;
SET GLOBAL min_examined_row_limit = 1000;
注意:在 MySQL 8.0+ 中,
log_queries_not_using_indexes 已更名为 log_slow_extra,但旧名称仍兼容。建议同时监控磁盘空间,避免日志文件撑满数据盘。
4.2 慢查询日志分析工具对比
原始慢查询日志是纯文本格式,可读性差。业界主流使用 mysqldumpslow(MySQL 自带)和 pt-query-digest(Percona Toolkit)进行聚合分析。
| 特性 | mysqldumpslow | pt-query-digest |
|---|---|---|
| 安装方式 | MySQL 自带,无需额外安装 | 需安装 Percona Toolkit |
| 聚合能力 | 按 SQL 指纹聚合,支持排序 | 按指纹聚合,支持多维排序、过滤 |
| 输出格式 | 文本表格 | 文本报告 / JSON / 树形图 |
| 查询时间统计 | 总时间、平均时间、最大时间 | 总时间、平均时间、中位数、95 百分位、标准差 |
| 锁等待分析 | 不直接支持 | 支持 Lock Time 统计 |
| 行数分析 | 支持 Rows_examined / Rows_sent | 支持 Rows_examined / Rows_sent / Rows_affected |
| 适用场景 | 快速查看 Top N 慢查询 | 深度分析、报表生成、自动化巡检 |
4.3 使用 mysqldumpslow 快速定位 Top SQL
mysqldumpslow 是 MySQL 自带的 Perl 脚本,位于 MySQL 安装目录的 bin/ 下。常用参数如下:
-s t:按查询总时间排序(默认)-s at:按平均查询时间排序-s c:按执行次数排序-t N:只显示前 N 条-g pattern:按正则过滤 SQL 文本-a:不将数字抽象为 N,显示原始值
实战命令示例:
# 查看总耗时最长的前 10 条慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log
# 查看平均耗时最长的前 5 条,并过滤包含 "score" 的表
mysqldumpslow -s at -t 5 -g "score" /var/log/mysql/slow-query.log
# 查看执行次数最多的前 3 条,保留原始数字
mysqldumpslow -s c -t 3 -a /var/log/mysql/slow-query.log
输出示例解读:
Count: 123 Time=2.34s (288s) Lock=0.01s (1.23s) Rows=1000.0 (123000)
SELECT * FROM score_rank WHERE batch_id = N ORDER BY score DESC LIMIT N
- Count:该 SQL 指纹被执行了 123 次
- Time=2.34s (288s):平均耗时 2.34 秒,总耗时 288 秒
- Lock=0.01s (1.23s):平均锁等待 0.01 秒,总锁等待 1.23 秒
- Rows=1000.0 (123000):平均扫描/返回 1000 行,总计 123000 行
4.4 使用 pt-query-digest 深度分析
pt-query-digest 是 Percona Toolkit 的核心工具,功能远超 mysqldumpslow。它不仅能分析慢查询日志,还能分析通用日志、二进制日志、tcpdump 抓包文件。
安装 Percona Toolkit(CentOS / Ubuntu):
# CentOS
yum install percona-toolkit
# Ubuntu
apt-get install percona-toolkit
常用分析命令:
# 分析慢查询日志,输出到终端
pt-query-digest /var/log/mysql/slow-query.log
# 分析慢查询日志,输出到文件
pt-query-digest /var/log/mysql/slow-query.log > /tmp/slow_report.txt
# 分析最近 1 小时的慢查询(配合时间过滤)
pt-query-digest --since '2025-01-01 10:00:00' --until '2025-01-01 11:00:00' /var/log/mysql/slow-query.log
# 分析并只显示前 5 个最慢的查询指纹
pt-query-digest --limit 5 /var/log/mysql/slow-query.log
# 分析并输出 JSON 格式(便于程序处理)
pt-query-digest --output json /var/log/mysql/slow-query.log
4.5 慢查询定位流程与 SVG 分析图
以下 SVG 图展示了从开启日志到定位慢 SQL 的完整分析流程:
4.6 定位慢 SQL 后的关键分析维度
当通过工具定位到具体的慢 SQL 后,需要从以下四个维度进行深度分析:
- 查询时间分布:查看平均时间、最大时间、95 百分位时间,判断是否存在偶发性的严重慢查询。
- 扫描行数与返回行数:如果
Rows_examined远大于Rows_sent,说明索引过滤性差,需要优化索引或改写 SQL。 - 锁等待时间:高锁等待通常意味着并发写冲突或行锁升级为表锁,需要检查事务隔离级别和索引使用。
- 查询频率:即使单次查询不慢,但高频执行也会累积大量耗时,这类 SQL 应优先考虑缓存或批量处理。
实战案例:某评分通道的
SELECT * FROM score_detail WHERE batch_id = ? AND user_id = ? ORDER BY create_time DESC LIMIT 1 在 mysqldumpslow 中显示总耗时排名第一。通过 pt-query-digest 进一步分析发现,该 SQL 平均扫描 50000 行但只返回 1 行。添加联合索引 (batch_id, user_id, create_time) 后,扫描行数降为 1 行,查询时间从 2.3 秒降至 0.003 秒。
4.7 慢查询日志的运维注意事项
- 日志轮转:使用
logrotate定期切割慢查询日志,避免单个文件过大。切割后执行mysqladmin flush-logs让 MySQL 重新打开日志文件。 - 采样策略:高并发场景下,建议将
long_query_time设置为 0.5~1 秒,并配合min_examined_row_limit过滤掉小表全表扫描的噪声。 - 安全审计:慢查询日志可能包含敏感数据(如用户 ID、手机号),生产环境应限制日志文件的访问权限,并定期清理。
- 自动化告警:结合
pt-query-digest的 JSON 输出,编写脚本定时分析慢查询,当新增慢 SQL 或总耗时突增时触发告警。
避坑指南:不要在生产数据库上直接执行
pt-query-digest 分析,建议将慢查询日志拷贝到分析服务器或使用 --processlist 模式从从库采集。另外,mysqldumpslow 在 MySQL 8.0 中已标记为废弃,推荐逐步迁移到 pt-query-digest。