慢查询日志无法捕获“偶尔慢”问题,因其仅记录单次执行超阈值的sql;真正原因常是锁等待、缓冲池冷启动、统计信息失真或临时磁盘排序,需结合rows_examined和explain分析。

慢查询日志不是“偶尔慢”时的万能开关——它只记录超过阈值的单次执行,而“偶尔慢”往往藏在长尾分布、资源争抢或统计信息失真里。
确认 slow_query_log 真正在记录哪些查询
很多人改完配置就以为日志开了,结果查了一圈没记录,其实是配置没落盘或被覆盖。关键看三件事:
-
SHOW VARIABLES LIKE 'slow_query_log'返回ON -
slow_query_log_file路径 MySQL 进程有写权限(比如/var/lib/mysql/mysql-slow.log不可写就会静默失败) -
long_query_time设为浮点数,如0.5或1.0;设成1s或整数1在某些旧版本会静默忽略 - 若
log_output = TABLE,得查mysql.slow_log表,且要关掉general_log(二者冲突)
为什么“偶尔慢”的 SQL 很可能根本没进慢日志
慢日志只按单次执行时间截断,但“偶尔慢”常由以下原因触发,它们不改变平均耗时,却让某几次严重拖慢:
- 并发高峰时锁等待堆积:
Lock_time高但Query_time未超阈值 → 日志里不出现 - InnoDB 缓冲池冷启动:第一次查大表没命中,后续就快了 → 只有首次进日志(如果刚好超阈值)
- 统计信息过期:
EXPLAIN显示rows=100,实际扫描 50 万行 → 执行计划选错,但单次仍可能 - 临时磁盘排序:
Extra: Using filesort+tmp_table_size不足 → 某次数据量突增才爆出来
这时光靠 mysqldumpslow 会漏掉——它只聚合“慢”的,不抓“偶发抖动”的。
用 pt-query-digest --explain 直击执行计划漂移
mysqldumpslow 合并同构 SQL(如 WHERE user_id = ?),掩盖参数差异带来的执行路径变化;而 pt-query-digest 加 --explain 能对每类指纹 SQL 自动补上 EXPLAIN 结果,直接暴露问题:
- 同一 SQL,不同参数下
type从ref变成ALL→ 索引失效信号 -
key字段有时是idx_status,有时是NULL→ 隐式类型转换或函数导致 -
rows预估和实际Rows_examined差 100 倍 → 必须ANALYZE TABLE更新统计信息
命令示例:pt-query-digest --explain h=localhost,u=root,p=xxx /var/lib/mysql/mysql-slow.log
Rows_examined 远大于 Rows_sent 是最实在的线索
慢日志里这行:# Query_time: 0.892134 Lock_time: 0.000045 Rows_sent: 1 Rows_examined: 98765 ——哪怕没超 long_query_time,也该立刻拉出来分析。
- 这是比
Query_time更底层的性能证据:MySQL 扫了近 10 万行才返回 1 行 - 常见诱因:
WHERE DATE(create_time) = '2024-01-01'(索引失效)、varchar字段跟数字比较(隐式转换)、OR连接多个非索引列 - 必须配合
EXPLAIN看type和key,不能只盯耗时
真正卡点不在“慢”,而在“扫得多、回得少”——这个信号容易被阈值过滤掉,得主动翻日志逐条看 Rows_examined。











