开启慢查询日志只是SQL性能治理的第一步,真正麻烦的是从成千上万条记录里找出那些反复出现、拖慢整体吞吐的高频语句。如果靠肉眼翻文件,不仅效率极低,还会因为参数不同把同一条模板SQL误判成多条。我们需要用聚合分析思路把日志变成可排序的指标。

一、慢查询日志的基础配置回顾
在MySQL中,慢查询日志由几个系统变量控制。最关键是slow_query_log开关、long_query_time阈值以及slow_query_log_file路径。只有先保证日志在正常写入,后续分析才有原材料。很多同学开了开关却忘了调阈值,结果日志为空或者体量过大。
下面是一段典型的环境变量设置,注意long_query_time设为0.5秒,意味着超过半秒的语句都会落盘。生产环境若设为0会记录全部SQL,一般不推荐。配置后可用SHOW VARIABLES LIKE 'slow%'确认生效情况。
-- 开启慢查询日志并设置阈值 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 0.5; SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; -- 确认配置 SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time';
二、为什么不能直接读日志文本
慢日志原始内容长这样:每条含时间戳、用户、SQL文本、执行时长、锁时间、扫描行数。同一业务模板可能因为入参不同而出现几百次,人工无法汇总。更严重的是,有些框架会把SQL换行写,肉眼切分语句边界很容易出错。
另一个误区是只盯着“单条最慢”的SQL。偶尔一次跑十秒的报表查询,对系统压力远小于每秒执行两百次、每次八十毫秒的下单接口。高频且总量大的语句才是优化性价比最高的目标,这就必须用工具做分组计数。
# 原始慢日志片段示例(已转义尖括号) # Time: 2023-09-01T10:00:01.123456Z # User@Host: app[app] @ [192.168.0.1] # Query_time: 0.082 Lock_time: 0.001 Rows_sent: 1 Rows_examined: 5000 SELECT * FROM order_tbl WHERE user_id=123 AND status=1;
三、使用 pt-query-digest 快速聚合
Percona Toolkit里的pt-query-digest是定位高频SQL的首选。它会解析日志,把指纹相同的SQL归并,输出按总耗时或执行次数排序的报告。报告里清楚列出某类语句的执行次数、占比、平均与最大耗时,一眼就能看到热点。
安装后执行一条命令即可。下面示例中--limit控制输出前十条,--order-by可按需要切换为cnt(次数)或query_time(耗时)。生成的报告头部还有整体统计,比如日志总语句数、唯一指纹数,帮助判断集中度。
# 安装工具(以Ubuntu为例) apt-get install percona-toolkit # 分析慢日志并按执行次数排前10 pt-query-digest --limit 10 --order-by cnt /var/log/mysql/slow.log > report.txt # 查看报告摘要 head -n 40 report.txt
报告里每个指纹块都有# Rank、# Count、# Exec time等信息。比如看到某SELECT指纹Count占全量60%,平均执行0.05秒,但每秒上百次,那它就是典型高频SQL。接下来优先给它加复合索引或改写法,收益最明显。
四、轻量方案:mysqldumpslow
如果服务器不能装第三方工具,MySQL自带的mysqldumpslow也能做基础聚合。它按SQL模板分组,支持按次数-c、按平均时间-a等排序。虽然不如pt-query-digest细致,但胜在零依赖。
下面命令取出执行次数最多的前五个模板。注意它把具体参数替换为N,便于归并。缺点是无法给出响应时间分布曲线,也难以过滤特定库表,适合做初步筛查。
# 按执行次数排前5 mysqldumpslow -s c -t 5 /var/log/mysql/slow.log # 按平均查询时间排前5 mysqldumpslow -s at -t 5 /var/log/mysql/slow.log
五、定位后的优化落地步骤
拿到高频SQL清单后,先拿原SQL进数据库跑EXPLAIN,看是否走索引、是否出现Using filesort或Using temporary。很多时候高频慢是因为缺失联合索引,或者查询条件对字段用了函数导致索引失效。
确认问题后,建索引或改写SQL,再回流到测试环境用相同日志模板压测。若Rows_examined明显下降、执行时间进入毫秒级,说明优化有效。最后把阈值调回业务可接受范围,避免日志无限膨胀。
-- 查看高频SQL的执行计划 EXPLAIN SELECT * FROM order_tbl WHERE user_id=123 AND status=1; -- 补充联合索引示例 ALTER TABLE order_tbl ADD INDEX idx_user_status (user_id, status);
| 工具 | 安装成本 | 聚合维度 | 适用场景 |
|---|---|---|---|
| pt-query-digest | 需装Percona Toolkit | 次数、耗时、锁、行数等 | 深度分析与报告 |
| mysqldumpslow | 数据库自带 | 次数、平均时间 | 快速初筛 |
六、常见坑与建议
有人把long_query_time设得太大,导致真正的高频轻量慢SQL不进日志,误以为系统很健康。建议初期设小一点,比如0.1到0.5秒,观察几天再调。另外日志文件要配轮转,否则磁盘写满会引发故障。
还有一点,定位高频SQL不是终点。若某语句来自烂代码里的循环查询,加索引只是缓解,根本做法是改成分批或join。分析时结合应用日志看调用链,才能从架构上消除瓶颈。
slow_query_logSQL优化pt_query_digest修改时间:2026-08-05 18:18:42