long_query_time不是设小就管用,它只统计mysql内核执行耗时,不包含网络延迟、客户端解析、锁等待(lock_time单独记),且会话级设置对已有连接无效;确认开启需查show variables like 'slow_query_log'返回on,并验证log_output、路径权限及云服务覆写。

直接说结论:long_query_time 不是“设小就管用”,它只统计 MySQL 内核执行耗时,不包含网络延迟、客户端解析、锁等待(Lock_time 单独记),且会话级设置对已有连接无效。
怎么确认慢查询日志真开启了?
别只信配置文件里写了 slow_query_log = 1,得查运行时状态:
- 执行
SHOW VARIABLES LIKE 'slow_query_log',返回值必须是ON(不是1或TRUE); - 同时检查
slow_query_log_file路径是否存在、MySQL 进程是否有写权限(常见坑:/var/log/mysql/目录不存在,或 SELinux 拦截); - 如果
log_output设为TABLE,还要确认mysql.slow_log表引擎不是CSV(它不支持写入),且该表可写; - 云数据库(如阿里云 RDS、腾讯云 CDB)可能覆写参数,需进控制台确认是否真正启用,不能只依赖
SET GLOBAL。
long_query_time 设多少才合理?
设成 0.1 看似“更敏感”,实际容易漏掉真实瓶颈,还可能压垮磁盘 I/O:
- MySQL 5.7 及以前版本对
long_query_time向下取整,设0.9实际按0处理(即所有语句都记); - 高并发 OLTP 场景下,建议从
2.0起步,验证后再逐步调低; - 设低于
0.5时,务必同步关掉log_queries_not_using_indexes,否则未走索引但很快的语句(如SELECT COUNT(*) FROM config)会大量刷日志; - 真正卡顿但没进日志?先看
Lock_time—— 如果Query_time是 0.3s、Lock_time是 1.8s,说明是锁争用,不是 SQL 本身慢。
为什么 SELECT * FROM orders WHERE status = 'pending' 明显卡却没进日志?
这是最常被误判的场景,原因往往不在阈值本身:
-
long_query_time是会话级变量:你用SET SESSION long_query_time = 1,只影响当前连接;新连接仍用全局值,必须用SET GLOBAL long_query_time = 1; - 该语句可能走了索引,
Rows_examined很小,但因 MVCC 版本链过长或二级索引回表多,实际执行慢——Query_time仍可能低于阈值; - 如果用了代理(如 ProxySQL、MyCat),SQL 在代理层解析/路由耗时不会计入
Query_time,得在代理侧开自己的慢日志; - 事务中执行的语句,其
Query_time从语句开始执行算起,但若前面有大事务未提交,锁等待时间不计入,只记在Lock_time里。
如何验证配置生效并抓到可控慢 SQL?
别等线上出问题再试,用可控手段验证:
- 先查当前值:
SHOW VARIABLES LIKE 'long_query_time'(注意返回的是 float,比如2.000000); - 临时调低:
SET GLOBAL long_query_time = 2.0; - 强制触发:
SELECT SLEEP(2.1),然后立刻查日志:tail -n 5 /var/log/mysql/mysql-slow.log或SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 1; - 如果没记录,立刻检查:
slow_query_log是否真为ON、log_output是否匹配输出方式、日志路径父目录是否存在且可写; - 生产环境避免长期设
long_query_time ,除非你已配好日志轮转(<code>logrotate)和专用分析流程(如pt-query-digest)。
最容易被忽略的一点:慢查询日志只告诉你“哪条 SQL 慢”,但从不解释“为什么慢”——Rows_examined 和 Rows_sent 的比值、是否走了索引、执行计划有没有 Using filesort/Using temporary,这些必须配合 EXPLAIN 和 SHOW PROFILE 才能定位。日志只是起点,不是终点。











