SHOW STATUS无法监控存储过程内存占用,因其无对应变量,且存储过程本身不分配独立内存,真正消耗内存的是其内部SQL(如游标、临时表、排序缓冲区);必须通过performance_schema按线程追踪events_statements_history_long与memory_summary_by_thread_by_event_name等表定位。

SHOW STATUS 无法直接监控存储过程内存占用
MySQL 的 SHOW STATUS 不提供任何与“存储过程内存占用”直接对应的变量,比如 proc_memory_used 或 sp_rss 这类字段根本不存在。存储过程本身不分配独立内存块——它只是 SQL 执行的封装,真正吃内存的是它内部执行的语句(如大结果集的 SELECT、隐式临时表、游标缓存、排序缓冲区等)。指望 SHOW STATUS 看出某个存储过程占了多少内存,就像想用汽车仪表盘读出司机午餐吃了几口饭一样,不在同一层。
为什么 Threads_running 和 Questions 都不能定位存储过程资源消耗
这两个常被误用的指标其实和存储过程内存无直接因果关系:
-
Threads_running只表示当前正在执行语句的线程数,哪怕一个存储过程只做SELECT 1,它也会让该值 +1;反之,一个慢存储过程若卡在锁等待或 I/O 上,Threads_running可能早已降为 0,但内存早已被其打开的游标或临时表占住 -
Questions统计客户端发来的原始语句数,CALL proc_name()算 1 次,但 proc 内部执行了 50 条INSERT和 3 次ORDER BY,这些都不计入Questions,却实实在在消耗 sort_buffer_size 和 tmp_table_size
更麻烦的是:SHOW STATUS 所有内存相关变量(如 Innodb_buffer_pool_pages_data、Key_blocks_used)都是全局累计或池级统计,无法按线程、按存储过程拆分。
真正可行的路径:performance_schema + 线程追踪
要定位某次 CALL 的实际内存开销,必须跳出 SHOW STATUS,走以下链路:
- 先确认 performance_schema 已启用且关键 instrument 开启:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME IN ('statement/sql/call', 'statement/sql/select', 'statement/sql/insert', 'memory/sql/TABLE'); - 查出正在运行的存储过程调用:
SELECT THREAD_ID, SQL_TEXT FROM performance_schema.events_statements_current WHERE EVENT_NAME = 'statement/sql/call'; - 用拿到的
THREAD_ID去查它最近执行过的子语句:SELECT SQL_TEXT, DIGEST_TEXT, TIMER_WAIT/1000000000000 AS sec, WORK_COMPLETED FROM performance_schema.events_statements_history_long WHERE THREAD_ID = ? AND EVENT_NAME != 'statement/sql/call' ORDER BY TIMER_START DESC LIMIT 10;—— 注意WORK_COMPLETED字段(MySQL 8.0.30+)会显示排序/分组使用的内存量(单位字节),这是最接近“内存占用”的直接线索 - 若需更细粒度,结合
performance_schema.memory_summary_by_thread_by_event_name,过滤对应THREAD_ID,看COUNT_ALLOC和SUM_NUMBER_OF_BYTES_ALLOC在调用期间是否突增
这个流程没法一键完成,必须关联多张表、注意时间窗口,并且依赖 performance_schema 的采集粒度和历史保留配置(events_statements_history_long 默认只存 1 万条,容易被刷掉)。
容易被忽略的关键点
很多团队卡在第一步就失败,不是因为不会写 SQL,而是忽略了三个硬性前提:
- MySQL 版本必须 ≥ 8.0.14(
WORK_COMPLETED字段才稳定支持内存统计),5.7 或早期 8.0 即使开了 instrument,也拿不到具体字节数 -
performance_schema启动时必须加载 memory instruments,仅靠运行时UPDATE setup_instruments不够——要检查mysqld启动参数是否含--performance-schema-instrument='memory/%=ON' - 存储过程中若用了
PREPARE/EXECUTE动态 SQL,它的执行记录会出现在events_statements_*中,但归属线程仍是调用者线程,这点容易误判为“其他连接干的”
所以,别在 SHOW STATUS 里找答案。它连存储过程是否在跑都回答不了,更别说内存了。


















