必须用performance_schema查线程级细节才能准确定位存储过程卡点:先用show full processlist筛选command为execute、state非sleep且info含call的语句,再通过events_statements_current验证是否真在执行,最后结合events_statements_history_long、sys.io_by_thread_by_bytes和sys.memory_by_thread_by_current_bytes分析内部sql、i/o与内存消耗。

不能只看 SHOW PROCESSLIST,它只能告诉你“CALL 在跑”,但看不出 CPU、内存、I/O 谁在扛;真要定位卡点,必须切到 performance_schema 查线程级细节。
查当前正在执行的 CALL 语句(SHOW FULL PROCESSLIST 级)
这是最快的人工响应动作,适合快速识别“谁卡住了”:
-
Command字段为Execute,且State不是Sleep,同时Info包含CALL—— 这才是真正的存储过程调用中 -
Time超过 30 秒就要盯住,60 秒以上基本可考虑KILL QUERY Id(注意不是KILL Id,后者会断连接) - 如果
Info显示为NULL,说明语句已结束或被截断,PROCESSLIST此时失效,必须转向performance_schema
确认 CALL 是否真在执行(events_statements_current)
避免误判:有些 SQL 文本里恰好含 CALL 字符串,但并非真正调用存储过程。这一步能验证入口是否活跃:
- 执行:
SELECT THREAD_ID, SQL_TEXT, TIMER_WAIT/1000000000000 AS sec FROM performance_schema.events_statements_current WHERE EVENT_NAME = 'statement/sql/call' -
TIMER_WAIT单位是皮秒,不除以1000000000000就是一串不可读数字 - 返回为空?检查
setup_instruments是否启用:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'statement/sql/call'
顺着线程 ID 挖内部 SQL 和资源消耗(events_statements_history_long + sys 视图)
存储过程本身不耗资源,真正吃 CPU、刷磁盘的是它内部的 SELECT、INSERT、游标循环或隐式临时表。这步才能看到根因:
- 用上一步拿到的
THREAD_ID查events_statements_history_long,过滤出EVENT_NAME非call的语句,看哪些DIGEST_TEXT扫描行数多、TIMER_WAIT高 - 查 I/O 压力:
SELECT * FROM sys.io_by_thread_by_bytes WHERE thread LIKE '%CALL%' ORDER BY total DESC LIMIT 3 - 查内存分配:
SELECT user, current_allocated FROM sys.memory_by_thread_by_current_bytes m JOIN sys.session s ON m.thread_id = s.thd_id WHERE s.current_statement LIKE 'CALL%' - 若返回空,要么线程已结束,要么
memory/%类 instruments 没开:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%'
容易被忽略的关键前提
performance_schema 必须为 ON(查 SELECT @@performance_schema),且关键消费者要启用:events_statements_history_long、events_statements_current、events_waits_current。没有这些,你看到的只是“有 CALL”,而不是“它干了什么、花了多少、卡在哪”。











