MySQL存储过程调用本身不触发慢查询日志,真正被记录的是过程内执行的SQL语句,但需显式开启log_slow_sp_statements=ON(默认OFF),否则仅CALL语句被判定且几乎总不超阈值。

log_slow_sp_statements 默认是 OFF
MySQL 5.7 默认不记录存储过程体内的 SQL 语句,根本原因是 log_slow_sp_statements 变量默认为 OFF。这个开关控制「是否对存储过程内部每条语句单独做慢查询判定」。关着的时候,慢日志只看顶层的 CALL proc_name() 这条语句——它本身执行极快(通常 long_query_time 阈值,所以整条记录都不会出现。
开启它才能让过程内真实的 SELECT、UPDATE 等语句按自身耗时独立判断是否进日志:
-
SET GLOBAL log_slow_sp_statements = ON;(需 SUPER 权限,仅对新连接生效) - 或在
my.cnf的[mysqld]段加log_slow_sp_statements = ON,然后重启
开了 log_slow_sp_statements 还没日志?检查三件事
即使打开了 log_slow_sp_statements,仍可能看不到过程内 SQL 的慢日志,常见卡点如下:
-
slow_query_log本身是OFF:这个总开关没开,其他全白搭。执行SHOW VARIABLES LIKE 'slow_query_log';确认返回ON -
log_output是NONE:默认不输出到任何地方。必须设为FILE或TABLE,例如SET GLOBAL log_output = 'FILE'; -
slow_query_log_file路径不可写:MySQL 进程(通常是mysql用户)对该路径无写权限,或目录不存在,日志会静默失败。用ls -l $(dirname $(mysql -Nse "SELECT @@slow_query_log_file"))检查
为什么 SHOW PROFILES 比慢日志更适合定位过程瓶颈
慢日志依赖时间阈值,而存储过程里常有游标循环 + 多次小查询的组合,单次都不超 long_query_time,但累积很慢——这种场景下慢日志完全空白,但业务就是卡。
这时 profiling 更直接:
- 先
SET profiling = 1; - 再
CALL your_proc(); - 执行
SHOW PROFILES;找到对应 Query_ID - 用
SHOW PROFILE FOR QUERY N;查每个阶段耗时,比如Sending data、Copying to tmp table卡在哪一步
注意:profiling 是调试用,生产环境别长期开着,性能开销明显。
performance_schema 是更可靠的长期方案
如果需要持续监控存储过程内部 SQL,performance_schema 比慢日志更准,且不受 log_slow_sp_statements 开关限制(只要语句真实执行了):
- 确保
events_statements_history_longconsumer 已启用:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long'; - 执行过程后,查:
SELECT SQL_TEXT, TIMER_WAIT/1000000000 AS sec FROM performance_schema.events_statements_history_long WHERE SQL_TEXT LIKE '%your_table%' ORDER BY TIMER_WAIT DESC LIMIT 5; - 注意:
TIMER_WAIT单位是皮秒,除以1e9得秒数;过滤时用SQL_TEXT比用过程名更稳,因为过程调用本身不进这里
真正容易被忽略的是:慢日志不是“记录慢操作”的唯一手段,尤其对存储过程——它只记录满足阈值的单条语句,而过程的性能问题往往藏在组合逻辑、锁等待或资源争用里,这些得靠 performance_schema 或 SHOW PROFILE 去挖。


















