应查 Performance Schema 的 events_statements_summary_by_program 表,它能全局统计所有存储过程的执行次数、总耗时和平均耗时;需确保相关 instruments 和 consumers 已启用,并授权 SELECT 权限。

直接查 Performance Schema 的 events_statements_summary_by_program
MySQL 8.0 中,SHOW PROFILE 已被标记为 deprecated,且只对当前 session 有效、不跨调用累计,不能用于统计「所有存储过程」的耗时与频率。真正能稳定采集全局数据的是 performance_schema,只要它已启用(默认开启),就能持续记录每个存储过程的执行次数、总耗时、平均耗时等。
关键查询语句:
SELECT OBJECT_SCHEMA AS db, OBJECT_NAME AS proc_name, COUNT_STAR AS exec_count, ROUND(SUM_TIMER_WAIT / 1000000000, 3) AS total_sec, ROUND(AVG_TIMER_WAIT / 1000000000, 3) AS avg_sec FROM performance_schema.events_statements_summary_by_program WHERE OBJECT_TYPE = 'PROCEDURE' AND COUNT_STAR > 0 ORDER BY SUM_TIMER_WAIT DESC;
注意点:
-
OBJECT_SCHEMA是存储过程所在的数据库名,不是调用方所在库 - 结果中
COUNT_STAR是自上次重置以来的总执行次数,不是实时 QPS - 若某过程没出现在结果里,说明它尚未被执行过,或
performance_schema.setup_instruments中未启用相关 instrument - 必须确保
setup_instruments中的 stored procedure 相关项已开启:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE '%stored%';
为什么不能用 SHOW PROFILES 或慢日志替代
SHOW PROFILES 和 SHOW PROFILE FOR QUERY N 只保留当前 session 最近 15 条(默认)的 profile 记录,且不区分存储过程名,只显示 CALL xxx() 这一行的阶段耗时,无法聚合、无法跨会话、无法导出历史趋势。
慢查询日志(slow_query_log)默认只记录单条 SQL,而存储过程内部的语句不会以「CALL」形式写入慢日志——除非你把 log_slow_sp_statements = ON(MySQL 8.0.23+ 才支持),但它只记录「存储过程本身执行超时」,不记录内部 SQL,且默认关闭、不统计频率。
常见误操作:
- 执行
SET profiling = 1后去查其他 session 的过程耗时 → 查不到,profile 是 session 级的 - 在慢日志里搜
CALL my_proc想看调用频次 → 基本为空,因为慢日志不默认记录 CALL 语句 - 用
SHOW GLOBAL STATUS LIKE 'Com_call%'→ MySQL 根本没有这个状态变量,Com_系列只覆盖 DML/DDL,不包含存储过程调用
如何补全「谁在什么时候调用了哪个过程」的上下文
events_statements_summary_by_program 给的是聚合统计,但缺少调用者、时间戳、参数值等上下文。要补全这些,得结合其他表:
临时抓取最近几次调用详情(需提前开启相关 consumers):
SELECT t.THREAD_ID, p.OBJECT_NAME AS proc_name, p.OBJECT_SCHEMA AS db, p.TIMER_START / 1000000000 AS start_ts, p.TIMER_END / 1000000000 AS end_ts, ROUND((p.TIMER_END - p.TIMER_START) / 1000000000, 3) AS duration_sec, s.PROCESSLIST_USER AS caller_user, s.PROCESSLIST_HOST AS caller_host FROM performance_schema.events_statements_history_long p JOIN performance_schema.threads t ON p.THREAD_ID = t.THREAD_ID JOIN performance_schema.processlist s ON t.THREAD_ID = s.THREAD_ID WHERE p.EVENT_NAME = 'statement/sql/call_procedure' AND p.OBJECT_NAME IS NOT NULL ORDER BY p.TIMER_START DESC LIMIT 10;
注意前提:
-
events_statements_history_long默认禁用,需先开:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long'; - 该表有容量限制(默认 10000 行),高频调用下旧记录会被覆盖
- 它不记录传入参数值,参数信息完全丢失——这是 MySQL 的设计限制,无法绕过
容易被忽略的初始化和权限问题
即使你知道查哪张表,第一次执行时很可能返回空结果,不是没数据,而是没开对东西。
必须确认并执行的最小初始化步骤:
- 检查 performance_schema 是否启用:
SELECT @@performance_schema;→ 必须为1 - 确认 instruments 开启:
SELECT COUNT(*) FROM performance_schema.setup_instruments WHERE NAME LIKE '%stored%' AND ENABLED = 'YES';→ 至少返回 2 行(如statement/sp/call_procedure,statement/sp/statement) - 确认 consumers 开启:
SELECT * FROM performance_schema.setup_consumers WHERE NAME IN ('events_statements_current', 'events_statements_history_long') AND ENABLED = 'YES'; - 账号需有
SELECT权限在performance_schema库,普通账号默认没有,需显式授权:GRANT SELECT ON performance_schema.* TO 'your_user'@'%';
最常卡住的地方:开了 performance_schema,但忘了开 statement/sp/call_procedure 这个 instrument,导致所有 CALL 都不被采集——它不像普通 SQL 那样自动包含在通配规则里,必须单独启用。


















