不能。performance schema不直接统计存储过程qps,因events_statements_summary_by_digest等表会将call拆解为内部语句而丢失上下文;需启用statement/sql/call instrument并查询events_statements_history_long中event_name='statement/sql/call'的原始事件进行分钟级频次统计。

存储过程本身不被单独计费,真正要盯的是它跑出来的SQL
MySQL的performance_schema不会把CALL proc_name()当作一个“资源容器”来统计——它只记录这条CALL语句的摘要和耗时,而过程内部所有SELECT、INSERT、UPDATE、游标循环、临时表创建等操作,才是实际吃CPU、内存、I/O的元凶。所以监控目标不是“存储过程”,而是“这个CALL背后激活了哪些线程、执行了哪些语句、分配了多少内存、刷了多少磁盘”。
必须确保以下基础已启用:
-
performance_schema = ON(检查:SELECT @@performance_schema) - 关键消费者开启:
events_statements_history_long、events_statements_current、events_waits_current - 内存仪器(memory instruments)需手动打开:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%';
查最近最耗时的CALL语句及其线程ID
先定位可疑入口:
SELECT DIGEST_TEXT, COUNT_STAR, SUM_TIMER_WAIT, AVG_TIMER_WAIT FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT LIKE 'CALL%' ORDER BY SUM_TIMER_WAIT DESC LIMIT 5;
拿到高耗时DIGEST后,不能只看这一行——它只是个聚合摘要。下一步必须查具体执行实例:
- 用
DIGEST反查events_statements_history_long,过滤出THREAD_ID和EVENT_ID - 再用
THREAD_ID关联performance_schema.threads,确认PROCESSLIST_USER、PROCESSLIST_HOST、PROCESSLIST_DB,排除是后台线程或系统任务 - 若
PROCESSLIST_STATE = 'Sleep',说明调用已结束,只能靠历史记录;若仍是'Executing',可进一步抓实时等待事件
顺着线程ID查它干了什么:SQL级I/O与内存
有了线程ID(比如12345),直接用sys schema快速下钻:
- 查该线程引发的磁盘I/O最多的是哪几条SQL:
SELECT * FROM sys.io_by_thread_by_bytes WHERE thread_id = 12345 ORDER BY total DESC LIMIT 3; - 查该线程当前内存占用(注意:仅反映“正在使用中”的内存块):
SELECT current_allocated, current_count_used, current_statement FROM sys.memory_by_thread_by_current_bytes WHERE thread_id = 12345; - 如果返回空,不是没数据,而是:
— 线程已退出(threads.THREAD_ID已消失)
— 或memory/%仪器没开(前面漏了setup_instruments那步)
— 或语句已执行完,内存已释放
别被CALL慢误导:重点排查隐式临时表和索引缺失
看到CALL my_report_proc平均耗时8秒,第一反应不该是翻存储过程源码,而是立刻验证它是否在反复创建隐式临时表:
- 查
SHOW STATUS LIKE 'Created_tmp%tables';,对比高峰期前后增量 - 用
EXPLAIN FORMAT=JSON重放过程内关键查询,看used_temp_table、using_filesort是否高频出现 - 查
sys.statements_with_full_table_scans,确认是否有未走索引的SELECT在循环里反复执行 - 游标遍历大表时,若没加
WHERE条件或没控制FETCH数量,很容易触发大量Handler_read_next和内存暴涨
真正难发现的,是那些“单次不慢、但每分钟调用200次”的存储过程——它们不会出现在events_statements_summary_by_digest的Top 5里,却能把memory/sql/TABLE或memory/innodb/buf_pool悄悄顶满。这时候得靠sys.memory_by_user_by_current_bytes按用户维度横向比对,或者用pidstat -d 1观察mysqld进程的持续I/O毛刺。











