必须先确认 slow_query_log 已开启,否则 long_query_time 再怎么调也没用;验证需执行 SHOW VARIABLES LIKE 'slow_query_log' 确认返回值为 ON,且动态设置后仅对新连接生效,配置文件修改必须重启 mysqld 才生效。

必须先确认 slow_query_log 已开启,否则 long_query_time 再怎么调也没用。
如何验证 slow_query_log 是否真正生效
很多人改了 long_query_time 却看不到日志,根本原因是 slow_query_log 还是 OFF。MySQL 默认关闭该功能,且动态设置后需注意作用域:
-
SET GLOBAL slow_query_log = 'ON'仅对新连接生效,已存在的连接不会自动继承 - 执行后务必检查:
SHOW VARIABLES LIKE 'slow_query_log'—— 返回值必须是ON,不是1或空 - 如果用配置文件(
my.cnf)修改,改完必须重启 MySQL 实例,systemctl restart mysqld不等于“重载”,不重启无效 - 某些云数据库(如阿里云 RDS、腾讯云 CDB)禁用
SET GLOBAL,只能通过控制台或参数模板修改,且可能有白名单限制
long_query_time 设多少才合理
设成 0 并不等于“记录所有查询”,它只表示“记录执行时间 > 0 秒的语句”,但实际受微秒精度和日志格式影响:
- 写入文件时,
long_query_time = 0.1是可行的(支持微秒级,如0.100000);写入mysql.slow_log表时,只保留整数秒,0.1会被截断为0,等效于全量记录(含极快查询),极易撑爆表 - 生产环境建议从
1或2开始,而不是盲目压到0.2;高并发 OLTP 场景下,0.5可能已产生大量日志,需同步评估磁盘 I/O 和归档策略 -
long_query_time是“执行时间”,不含连接建立、网络传输、客户端解析耗时;如果某 SQL 在监控里显示 3s,但慢日志没记录,大概率是它在排队等待锁(Lock_time高),而非执行本身慢
为什么 INSERT/UPDATE 不进慢日志,即使执行了 10 秒
这是默认行为,不是 bug。MySQL 慢查询日志只捕获 SELECT 类语句(包括 SELECT ... FOR UPDATE),而 INSERT、UPDATE、DELETE 等写操作默认不记录,无论多慢:
- 要让写操作也进日志,必须显式开启:
SET GLOBAL log_slow_admin_statements = 'ON'(注意名字不是log_slow_write_statements,别拼错) - 该参数同时影响
ALTER TABLE、ANALYZE TABLE等管理语句,所以开启前确认你真需要这些——它们可能高频出现且无业务意义 - 即便开了,
log_slow_admin_statements也不覆盖普通 DML;真正让UPDATE入日志的是另一个隐含逻辑:只有当它被当作“管理语句”执行(例如带FOR UPDATE的子查询中嵌套更新),才可能触发。更可靠的做法是用performance_schema.events_statements_history_long或代理层(如 ProxySQL)抓全量语句
日志里看到 # Query_time: 但没 # Lock_time:,说明什么
这通常意味着查询慢在执行本身(CPU/IO),而不是锁等待。但要注意两个常见干扰项:
- 如果
log_output = TABLE,mysql.slow_log表里没有Lock_time字段,所有锁信息丢失,无法判断瓶颈类型;必须切回FILE格式才能看到完整头部 -
mysqldumpslow默认合并不同参数的同模板 SQL(如WHERE id = 1和WHERE id = 100000都算一条),掩盖了“个别参数引发全表扫描”的问题;要用mysqldumpslow -s t -t 10 -a /path/to/slow.log加-a显示原始值 - 有些慢查询根本不会写入慢日志——比如执行过程中被
KILL中断,或因内存不足被 OOM killer 杀掉,此时得查错误日志(error_log)或performance_schema的 statement digest
最易被忽略的一点:long_query_time 是会话级变量,但它的全局值只影响新连接;如果你用连接池(如 HikariCP),旧连接可能仍沿用启动时的旧阈值,导致部分慢 SQL 漏捕获。上线前务必在应用侧执行一次 SELECT SLEEP(3) 验证是否真进了日志。


















