mysql存储过程调用本身不触发慢查询日志,真正可能被记录的是过程内执行的sql语句,但需开启log_slow_sp_statements=on(默认关闭),否则仅call语句(几乎不耗时)会被判断,导致慢操作漏记。

MySQL存储过程调用本身不触发慢查询日志
慢查询日志(slow_query_log)记录的是「执行时间超过 long_query_time 的 SQL 语句」,而不是存储过程的调用动作。也就是说,CALL proc_name() 这条语句本身几乎不耗时,它不会被记入慢日志——真正可能被记录的,是存储过程中执行的那些 SELECT/UPDATE/INSERT 等内部语句。
但有个关键前提:必须开启 log_slow_sp_statements = ON(MySQL 5.7.2+ / 8.0 默认关闭)。否则,即使存储过程里某条 SELECT 跑了 10 秒,只要它没单独出现在客户端请求中,就不会进慢日志。
-
log_slow_sp_statements = OFF(默认):过程内语句不记慢日志,只记顶层语句(即CALL)——而CALL几乎总在阈值内,所以“看起来”没记录 -
log_slow_sp_statements = ON:过程体内每条符合条件的语句,都按自身执行时间独立判断是否写入慢日志 - 该变量动态可设:
SET GLOBAL log_slow_sp_statements = ON,但需 SUPER 权限
如何确认某次存储过程调用是否真有慢操作
不能只看慢日志有没有 CALL 记录,得进过程体里逐条排查。最直接的方式是打开 profiling(仅用于调试,勿开在生产)或使用 performance_schema。
- 启用 profiling 后执行:
CALL your_proc(),再查SHOW PROFILES和SHOW PROFILE FOR QUERY N,能看到各阶段耗时,定位哪一步卡住 - 更推荐用
performance_schema.events_statements_history_long,过滤EVENT_NAME LIKE 'statement/sql/%'且SQL_TEXT包含过程名,能抓到真实执行的语句和TIMER_WAIT - 注意:
performance_schema默认不收集所有事件,需确保setup_consumers中events_statements_history_long是ENABLED
常见误判场景:为什么“明明很慢”却没进慢日志
不是日志漏了,而是条件没满足。几个高频原因:
-
long_query_time设得太高(比如 10 秒),而过程里最慢的语句只跑了 8 秒 → 不记 - 语句被缓存命中(
query_cache_type=ON且命中),MySQL 会跳过慢日志判定逻辑(即使结果集大、解析慢) - 过程里用了游标循环 + 多次小查询,单次都不超阈值,但累积耗时很长 → 每条都“合法”,慢日志里一条不显示
- 开启了
log_queries_not_using_indexes,但误以为它和慢日志联动;其实它只记未走索引的查询,和执行时间无关
监控存储过程性能的实用建议
别依赖慢日志做唯一依据。过程是黑盒,得从入口、中间、出口三层打点:
- 在过程开头加
SELECT NOW(6) INTO @start_time;,结尾算差值,用SELECT或写入日志表输出耗时 - 对关键子查询加
/*+ MAX_EXECUTION_TIME(3000) */提前中断(MySQL 5.7.8+),避免拖垮整个过程 - 用
sys.schema_table_statistics_with_buffer(sys schema 视图)查过程常访问的表是否有高io_read_requests或锁等待 - 如果过程频繁调用且参数固定,考虑用
PREPARE/EXECUTE预编译内部语句,减少解析开销
过程体越长,越容易掩盖真实瓶颈。别只盯着“CALL 是否慢”,要拆开看每一行 SQL 实际干了什么、读了多少行、等了多久锁。











