log_slow_sp_statements 默认为 OFF,导致存储过程内慢 SQL 不记录到慢查询日志;需显式开启该参数并确保 slow_query_log=ON、log_output 包含 FILE 才生效。

log_slow_sp_statements 默认是 OFF
存储过程体内的 SQL 语句默认不进慢查询日志,不是 MySQL 漏记,而是 log_slow_sp_statements 这个开关默认关闭。它从 MySQL 5.7.2 起引入,但即使你开了 slow_query_log,只要这个变量仍是 OFF,过程里跑 20 秒的 SELECT 也不会被记录——只有顶层的 CALL proc_name() 会被判断,而它本身几乎不耗时。
实操建议:
- 查当前状态:
SHOW VARIABLES LIKE 'log_slow_sp_statements';,确认值是OFF - 临时开启(需 SUPER 权限):
SET GLOBAL log_slow_sp_statements = ON; - 永久生效:在
my.cnf的[mysqld]段加一行log_slow_sp_statements = ON,然后重启 MySQL
慢日志根本没开,或 log_output 不是 FILE
很多人只调了 long_query_time,却忘了两个前置条件:slow_query_log 必须为 ON,且 log_output 必须包含 FILE。否则日志无处落脚,自然“空文件”。
常见误判现象:
-
SHOW VARIABLES LIKE 'slow_query_log';返回ON,但SHOW VARIABLES LIKE 'log_output';是TABLE或NONE→ 日志写进了表或直接丢弃 - 云数据库(如阿里云 RDS)可能禁用动态 SET,必须走控制台改参数模板
-
slow_query_log_file路径存在但不可写:MySQL 以mysql用户身份写入,不是你登录的账号;目录属主、SELinux、磁盘满都会静默失败
过程内语句单次不超阈值,但累积很慢
慢查询日志按「单条语句执行时间」独立判定,不累计。比如一个存储过程用游标循环执行 100 次 UPDATE,每次 0.4 秒(long_query_time = 1),每条都不记,但总耗时 40 秒——日志里干干净净。
这种场景下,不能靠慢日志发现瓶颈,得换方式:
- 用
performance_schema.events_statements_history_long查真实执行语句和TIMER_WAIT(单位皮秒),过滤SQL_TEXT含过程名 - 确保
setup_consumers中events_statements_history_long是ENABLED - 调试期可开
profiling:SET profiling = 1;,再CALL your_proc(),然后SHOW PROFILES和SHOW PROFILE FOR QUERY N
long_query_time 精度陷阱与管理语句豁免
设了 long_query_time = 0.1 却没日志?MySQL 对耗时不向上取整,差 1 纳秒就不记。系统调度、缓存命中、锁等待时间也不计入判定——这些都会让实际执行时间低于阈值。
另外,这几类语句天然绕过慢日志:
- 管理命令(
ALTER TABLE、ANALYZE TABLE):需显式开log_slow_admin_statements = ON - 未走索引的查询:默认不记,开
log_queries_not_using_indexes才可能捕获 - 扫描行数太少:
min_examined_row_limit > 0时,即使慢,rows_examined不达标也不记
真正难排查的是那种「过程里多条语句都卡在阈值边缘」的情况——它既不会触发慢日志,又拖垮整体响应,必须依赖 performance_schema 或应用层打点才能定位。


















