MySQL 8.0+ 慢查询日志默认关闭且输出至系统表,需显式设 log_output=’FILE’ 并配置 slow_query_log_file 才能写入文件;log_slow_extra 开启后格式变更导致 mysqldumpslow 解析失败,须用 8.0+ 版本或 pt-query-digest。

MySQL 8.0+ 慢查询日志默认关闭且格式变更
MySQL 5.7 升级到 8.0 后,slow_query_log 默认值从 ON 变为 OFF,且日志不再写入文件(除非显式配置),而是默认输出到系统表 mysql.slow_log(需启用 log_output = TABLE)。很多运维习惯性检查 /var/lib/mysql/hostname-slow.log 却发现文件为空,就是这个原因。
- 确认当前状态:
SELECT @@slow_query_log, @@long_query_time, @@log_output; - 若要恢复文件输出,必须同时设置:
SET GLOBAL slow_query_log = ON;
SET GLOBAL log_output = 'FILE';
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log'; -
long_query_time在 MySQL 8.0 中默认仍是10.0秒,但注意:该阈值现在按 ** 微秒精度 ** 判断(内部以微秒存储),且对包含锁等待的语句更敏感;实际生效值建议用SELECT @@long_query_time;确认,避免因会话级覆盖导致误判
mysqldumpslow 解析失败:日志格式不兼容
MySQL 8.0 的慢查询日志(尤其是开启 log_slow_extra 后)新增了 Rows_examined、Lock_time、Query_time 等字段,并采用 键值对 格式(如 # Rows_examined: 12345),而传统 mysqldumpslow(来自 MySQL 5.x 工具 包)无法识别这些行,直接跳过或报错解析失败。
- 验证日志格式是否含 extra 字段:
head -n 20 /var/log/mysql/mysql-slow.log | grep -E '^(# Time|Rows_examined|Lock_time)' - 解决方法 只有两个:
– 使用 MySQL 8.0 自带的mysqldumpslow(路径通常是/usr/bin/mysqldumpslow,确保版本 ≥ 8.0)
– 或改用更现代的分析工具,如pt-query-digest(Percona Toolkit),它原生支持 8.0 日志格式,且能聚合microsecond级时间、识别 prepared statement 占位符 - 若坚持用
mysqldumpslow,必须关闭log_slow_extra:SET GLOBAL log_slow_extra = OFF;,但这会丢失关键性能上下文(如是否命中索引、扫描行数等)
performance_schema.events_statements_summary_by_digest 不替代 slow_log
有人以为启用 performance_schema 就不用开慢日志了,这是误解。events_statements_summary_by_digest 表只保留最近的聚合摘要(受 performance_schema_digests_size 限制,默认 2000 条),且不记录原始 SQL 文本(仅 digest hash)、无详细时间戳、不保存执行计划信息。它适合实时监控 TOP SQL,但无法替代慢日志做归档分析或复现问题。
- 检查是否启用 digest 收集:
SELECT * FROM performance_schema.setup_consumers WHERE NAME = 'statements_digest';(需为
ENABLED) - 对比二者用途:
– 慢日志:完整语句 + 精确时间 + 错误码 + 扫描行数 → 用于根因分析、审计、合规
–events_statements_summary_by_digest:按 digest 分组的平均耗时 / 次数 → 用于发现高频低效模式 - 两者可并存,但不要互相替代;尤其在升级后,务必确认
slow_query_log已打开,否则可能漏掉偶发长事务或单次超时查询
升级后 log_queries_not_using_indexes 行为变化
该参数在 MySQL 8.0 中依然存在,但触发条件更严格:仅当语句满足「未使用任何索引」且「全表扫描行数 ≥ min_examined_row_limit」(默认 0)时才记录。更重要的是,它 ** 不记录 ** 使用了索引但效率低下的情况(如索引选择性差、回表过多),这类问题在 8.0 中更依赖 log_slow_extra 中的 Rows_examined 和 Rows_sent 对比来发现。
- 检查是否启用:
SELECT @@log_queries_not_using_indexes, @@min_examined_row_limit; - 常见误判场景:
–SELECT * FROM t WHERE status = ?(status 列有索引但基数极低)→ 不触发此日志,但实际很慢
– 此时应关注慢日志中Rows_examined: 1000000与Rows_sent: 10的巨大差异 - 建议组合使用:
SET GLOBAL log_slow_extra = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;,再配合
pt-query-digest --filter '$event->{Rows_examined} > 10000'定向筛查
慢查询日志不是“开了就行”,MySQL 8.0 把它从一个简单开关变成了需要理解字段语义、输出通道、工具链兼容性的性能基础设施。最容易被忽略的是 log_output 的默认值和 log_slow_extra 带来的格式断裂——这两点不手动确认,日志就等于没开。