必须写进my.cnf并重启mysql才能保障生产监控不中断,仅set global不可靠;需先执行show variables确认slow_query_log为on、long_query_time为浮点数(如1.0)、slow_query_log_file路径可写且权限正确,再配置slow_query_log=on、long_query_time=1.0、log_queries_not_using_indexes=off等参数并重启服务。

必须写进 my.cnf 并重启 MySQL,仅用 SET GLOBAL 无法保障生产监控不中断。
确认当前值再动手,别信默认或记忆
很多问题源于“以为设了,其实没生效”。先连上 MySQL 执行三句:
-
SHOW VARIABLES LIKE 'slow_query_log';—— 返回OFF?那日志根本不会写,调long_query_time没意义 -
SHOW VARIABLES LIKE 'long_query_time';—— 注意看类型:返回10(整型)说明之前设过整数,它被忽略;必须是1.0这种浮点数才生效 -
SHOW VARIABLES LIKE 'slow_query_log_file';—— 路径是否存在?MySQL 进程用户(通常是mysql)有没有权限写入?SELinux 或 AppArmor 可能静默拦截
配置文件里怎么写才真正生效
编辑 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf,在 [mysqld] 段落下添加这几行:
slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 1.0 log_queries_not_using_indexes = OFF
关键点:
-
slow_query_log = ON,不是1或TRUE,旧版本只认ON -
long_query_time = 1.0必须带小数点,1会被当整型丢弃(尤其在 MySQL 5.6 及更早版本中,0.5会变成0) -
slow_query_log_file显式指定路径,避免默认落在datadir下导致权限混乱;确保父目录存在且可写:sudo mkdir -p /var/log/mysql && sudo chown mysql:mysql /var/log/mysql -
log_queries_not_using_indexes = OFF是安全起点——它不看long_query_time,只要没走索引就记,容易撑爆磁盘;诊断阶段临时开,日常关掉
为什么 SET GLOBAL 看起来生效却不可靠
SET GLOBAL long_query_time = 1.0 确实能让新连接立刻用上,但有三个硬伤:
- 已存在的连接(比如 PHP-FPM 长连接池、Java 应用连接池)仍沿用创建时的会话值,不会自动刷新
- MySQL 重启后全部丢失,监控断档就是事故
- 某些版本(如 MySQL 8.0.14+)运行中用
SET GLOBAL修改后,配置文件里的值就被覆盖“作废”,下次重启反而回退到旧值
所以 SET GLOBAL 只适合快速验证,比如执行 SELECT SLEEP(2); 后立刻去查日志是否出现,但绝不能替代配置文件 + 重启。
阈值设多少才算合理
不是越小越好,也不是拍脑袋定数字,而是要对齐业务 RT 基线:
- 新上线服务建议从
1.0起步,跑一周看日志量和 DB CPU/IO 压力 - 如果核心接口 P95 RT 是
300ms,那long_query_time就该设成0.3 - 主从架构中,只在从库开慢日志,主库关掉——避免日志 IO 拖慢写入吞吐
-
long_query_time统计的是语句“执行完成耗时”,不含锁等待、网络传输、FLUSH TABLES等阻塞时间;看到某条SELECT耗时2.4s,未必是 SQL 本身慢,得结合performance_schema.events_statements_summary_by_digest查avg_timer_wait和sum_lock_time对比
真正难的不是设数字,而是区分“真慢”和“假慢”——锁等待高、IO 饱和、临时表落盘,这些都可能让一条简单 SQL 在慢日志里亮红灯,但优化方向完全不同。











