必须执行show variables like 'slow_query_log'确认返回on才真正启用,同时检查long_query_time(默认10秒,生产建议调至0.1~1)和slow_query_log_file路径是否可写,三者缺一不可。

如何确认慢查询日志当前是否启用及配置参数
直接查 slow_query_log 和 long_query_time 两个关键变量,别依赖配置文件是否写了——运行时可能被动态改过:
SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time'; SHOW VARIABLES LIKE 'slow_query_log_file';
注意:slow_query_log 是 ON/OFF 开关,但即使为 ON,若 long_query_time 设得过大(比如 10 秒),绝大多数慢 SQL 实际不会被捕获;MySQL 5.7+ 默认值是 10,生产环境通常要调到 0.1~1 之间才实用。
常见误判:看到 slow_query_log = ON 就以为日志在工作,却忽略了 long_query_time 实际设成了 5,而业务里真正卡顿的 SQL 多在 200ms 级别。
为什么设置了 long_query_time = 0.1 却仍没记录预期 SQL
有三个隐蔽原因常被忽略:
-
min_examined_row_limit非零时,扫描行数少于该值的语句不记日志(默认 0,但如果手动设过 1000,那只查 10 行的慢 JOIN 就会被跳过) -
log_queries_not_using_indexes开启后,会强制记录所有未走索引的查询,但它的触发不看执行时间——哪怕 1ms 也会写入,容易污染日志;关闭它才能让日志聚焦“真慢” - MySQL 8.0.14+ 引入了
log_throttle_queries_not_using_indexes,但对long_query_time生效的慢查无影响,不必纠结
建议操作顺序:先 SET GLOBAL long_query_time = 0.1;,再确认 min_examined_row_limit = 0,最后关掉 log_queries_not_using_indexes(除非你明确想追索引缺失问题)。
如何验证某条具体 SQL 是否会被慢日志捕获
不能靠猜,要用 SLOW_LOG 表或日志文件反查。但更高效的是用 SELECT SLEEP(0.2) 模拟慢操作来测试:
SET long_query_time = 0.1; SELECT SLEEP(0.2);
然后立刻检查日志文件(路径见 slow_query_log_file)是否新增一行。注意:该语句必须在非只读事务中执行,且客户端连接不能启用了 sql_log_off = ON。
另一个坑:long_query_time 是按「锁等待 + 执行时间」总和计算的,不是纯 CPU 时间。如果一条 SQL 因行锁卡了 800ms,执行本身只花 20ms,只要总耗时超阈值,它就会进日志——这点常被误认为“没慢为什么记了”。
MySQL 8.0 启用慢日志后日志文件为空的典型原因
最常踩的坑是权限与路径问题,尤其 Docker 或 systemd 管理的实例:
- MySQL 进程用户(如
mysql)对slow_query_log_file指定路径无写权限,日志静默失败(mysqld不报错,但tail -f看不到内容) - 配置里写了相对路径(如
./slow.log),实际写入位置是 mysqld 启动时的工作目录,不是 datadir - 开启了
log_output = TABLE(默认是FILE),此时日志写入mysql.slow_log表,需查表而非文件:SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 5;
建议始终用绝对路径配 slow_query_log_file,并确保该路径属主属组为 MySQL 运行用户;如用容器,挂载卷时注意 uid/gid 对齐。
真正难调试的,是那些刚过阈值、又恰好被并发或锁掩盖的 SQL——它们在日志里一闪而过,但线上抖动明显。这时候光看慢日志不够,得配合 performance_schema.events_statements_summary_by_digest 查平均延迟分布。











