必须确认slow_query_log为ON、slow_query_log_file路径可写、long_query_time值合理(如1.0),再用SELECT SLEEP(2)实测日志是否真实写入,三者缺一不可。

慢查询日志必须开,但不能乱开——关键在 long_query_time 的取值和生效时机,否则日志要么空转,要么爆炸。
如何确认当前慢查询日志是否真正启用
很多人执行 SET GLOBAL slow_query_log = ON 后就以为万事大吉,其实这只是“开了开关”,不等于日志正在写入。必须验证三件事:
-
SHOW VARIABLES LIKE 'slow_query_log'返回ON(不是1或空) -
SHOW VARIABLES LIKE 'slow_query_log_file'返回的路径存在、MySQL 进程有写权限(常见坑:路径目录不存在或 SELinux 拒绝写入) -
SHOW VARIABLES LIKE 'long_query_time'看到的是你期望的值,比如1.000000,而不是默认的10.000000
特别注意:slow_query_log_file 如果没指定绝对路径,MySQL 会写到数据目录下,文件名是 hostname-slow.log,容易被误删或和 binlog 混淆。
long_query_time 设多少才合理
设成 1 秒不是教条,而是现网收敛经验:它能覆盖绝大多数非预期延迟,又不至于淹没在噪音里。但要注意几个硬约束:
- 该参数最小可设为
0.1(100 毫秒),但低于 500 毫秒后,日志量陡增,尤其对高并发 OLTP 场景,可能压垮磁盘 IO 或日志轮转逻辑 -
long_query_time对已存在的连接不生效;新连接才会用新值。调试时务必用新客户端重连,或在当前会话执行SET long_query_time = 1临时覆盖 - 它只计算 SQL 执行时间,不含锁等待时间(MySQL 官方文档明确说明:lock acquisition time is not counted)。所以一条卡在行锁上的 UPDATE 可能执行时间很短,却因锁争抢导致业务超时,但它不会进慢日志
如果你怀疑是锁问题,得配合 SHOW ENGINE INNODB STATUS 或 performance_schema.data_locks 查,别只盯慢日志。
log_queries_not_using_indexes 别轻易开
这个参数看起来很“安全”——记录所有没走索引的查询,实际是典型的好心办坏事:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 小表全表扫描(比如
SELECT * FROM config WHERE type='app',表才 20 行)本就是最优解,却被记成“慢” - 某些 JOIN 条件字段有索引,但优化器因统计信息过期选了全表扫描,这类语句该修统计信息,不是加索引
- 开启后日志量可能翻几倍,真正耗时长的语句反而被刷屏掩盖
更可控的做法是关掉它,改用 min_examined_row_limit = 100:只记录扫描行数超过 100 行的语句。这个值可根据表平均大小动态调,比“有没有索引”更能反映真实代价。
配置生效后怎么验证日志真在写
别等线上出事再看。最直接的办法是手动生成一条“人工慢 SQL”:
SELECT SLEEP(2);
然后立刻检查日志文件:
- 用
tail -f /path/to/mysql-slow.log看是否追加了一条含# Time:、# User@Host:、# Query_time:的记录 - 重点核对
Query_time是否接近 2 秒,Lock_time是否为 0(因为SLEEP()不加锁) - 如果没出现,回头检查 MySQL 错误日志(
error.log),常有类似Could not write to slow log file的提示
还有一个隐性陷阱:MySQL 8.0+ 默认 log_output = FILE,但如果你改过 log_output = TABLE,那日志会写进 mysql.slow_log 表,而这个表默认是 CSV 引擎,写入性能差、查起来也慢,生产环境不推荐。










