存储过程本身不被慢查询日志记录,因call语句几乎不耗时;真正慢的是其内部sql,但默认不判定,需显式开启log_slow_sp_statements=on才生效。

存储过程本身不会被慢查询日志记录
慢查询日志只记录「执行时间超过 long_query_time 的 SQL 语句」,而 CALL proc_name() 这条语句本身几乎不耗时——它只是启动过程的入口,真正干活的是过程体内的 SELECT、UPDATE 等语句。这些内部语句默认不参与慢日志判定,所以你查日志,根本看不到过程名,更看不到哪一行慢。
log_slow_sp_statements 默认是 OFF
MySQL 5.7.2+ 和 8.0 中,控制是否对存储过程内部语句做慢查询判断的开关是 log_slow_sp_statements,但它默认关闭。这意味着即使过程里有一条 SELECT 跑了 15 秒,只要没单独执行,就不会进日志。
- 临时开启:
SET GLOBAL log_slow_sp_statements = ON;(需SUPER权限,仅对新连接生效) - 永久生效:在
my.cnf的[mysqld]段加log_slow_sp_statements = ON,然后重启 MySQL - 开了也没日志?再确认三件事:
slow_query_log = ON、log_output不是NONE、slow_query_log_file路径 MySQL 进程有写权限
即使开了,单次不超阈值的语句也不会记
存储过程里常见循环 + 小查询模式,比如游标遍历 1 万行,每次 INSERT 耗时 8ms(低于 long_query_time = 0.1),但总耗时 80 秒。慢日志一条都不会记,因为每条都“合法”。这种累积型性能问题,slow_query_log 天然无感。
-
SHOW PROFILES更适合这类场景:开profiling = 1后执行CALL,再用SHOW PROFILE FOR QUERY N查各阶段耗时 - 长期监控推荐
performance_schema.events_statements_history_long,它不依赖阈值,只要语句真实执行了就会留痕,且能精确到纳秒级 - 注意:
events_statements_history_long默认不启用,要先执行:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long';
EXPLAIN 不能直接作用于 CALL
EXPLAIN CALL proc_name() 是无效语法。你想知道哪句 SQL 慢,必须手动拆解:
- 用
SHOW CREATE PROCEDURE proc_name拿到完整定义 - 定位关键语句,把参数替换成真实值(如把
WHERE id = in_id改成WHERE id = 123) - 对这条具体语句跑
EXPLAIN,重点看type是否为ALL、key是否为NULL、rows是否远超实际匹配数 - 特别小心隐式转换:如果过程参数定义为
VARCHAR,但表字段是BIGINT,索引就直接失效
performance_schema 抓真实执行路径,再结合 EXPLAIN 验证单条语句。











