要确认“谁在调用”存储过程,应查询performance_schema.events_statements_current中event_name='statement/sql/call'的记录,结合thread_id关联threads表获取user、host等连接信息,并辅以routines静态扫描、触发器及事件调度器检查,覆盖显式调用、隐式触发和定时任务全路径。

直接查 performance_schema.events_statements_current 中的 CALL 语句
想确认“谁在调用”,不能只看 SHOW PROCEDURE STATUS——它只告诉你存储过程存在,不反映实时调用关系。真正能抓到调用方(比如某个业务接口、定时任务或应用连接)的,是 events_statements_current 表里正在执行的 CALL 记录。
执行这条语句就能看到当前活跃调用:
SELECT THREAD_ID, SQL_TEXT, USER, HOST, DB FROM performance_schema.events_statements_current WHERE EVENT_NAME = 'statement/sql/call';
注意点:
-
SQL_TEXT字段会显示完整调用语句,例如CALL proc_update_order_status(12345),从中可反推业务动作 -
USER和HOST能定位到具体应用连接来源(如app_payment@10.20.30.40),结合服务注册信息就能对应到业务系统 - 如果返回为空,先检查
setup_instruments是否启用:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'statement/sql/call'
从线程 ID 反查上层应用连接信息
光有 THREAD_ID 不够,得知道这个线程背后是谁发起的。MySQL 的 performance_schema.threads 表和 information_schema.PROCESSLIST 是关键跳板。
推荐组合查询:
SELECT t.PROCESSLIST_USER, t.PROCESSLIST_HOST, t.PROCESSLIST_DB, t.PROCESSLIST_INFO FROM performance_schema.threads t JOIN performance_schema.events_statements_current e ON t.THREAD_ID = e.THREAD_ID WHERE e.EVENT_NAME = 'statement/sql/call';
常见现象和判断依据:
-
PROCESSLIST_INFO如果是CALL xxx,说明该连接正处在调用中;如果是空或NULL,可能刚执行完或被截断,需结合events_statements_history_long确认最近行为 -
PROCESSLIST_USER值为api_order或batch_sync这类命名规范的账号,通常直接对应业务模块 - 如果多个线程共用同一个
USER(如都用app_rw),就得靠PROCESSLIST_HOST+ 应用日志交叉验证
用 INFORMATION_SCHEMA.Routines 关联调用表名做静态扫描
有些业务不会高频调用,但代码里写了固定调用逻辑(比如凌晨跑的统计任务)。这时实时监控抓不到,得靠静态分析:查哪些存储过程引用了特定业务表,再逆向推业务归属。
例如,要查谁在操作 orders 表:
SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM information_schema.routines WHERE ROUTINE_TYPE = 'PROCEDURE' AND ROUTINE_DEFINITION LIKE '%orders%';
更稳妥的做法是结合 mysql.proc 的 BODY 字段(虽然它是 BLOB,但 LIKE 仍可用):
SELECT db, name FROM mysql.proc WHERE type = 'PROCEDURE' AND body LIKE '%orders%';
风险提示:
-
LIKE匹配容易误中(比如字段名含orders_id但没调用表),必须人工核对SHOW CREATE PROCEDURE输出 - 部分客户端(如旧版 Navicat)无法直接查看
mysql.proc.body内容,建议用mysql -e命令行或 SQLyog - 若存储过程内使用动态 SQL(
CONCAT拼表名),这种文本扫描完全失效,只能靠日志或代理层埋点
别漏掉隐式调用场景:触发器与事件调度器
业务不一定显式写 CALL,也可能通过 INSERT/UPDATE 触发器间接调用,或由 EVENT 定时驱动。这两类容易被忽略。
查触发器是否调用存储过程:
SELECT EVENT_OBJECT_TABLE, ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE ACTION_STATEMENT LIKE '%CALL%';
查事件调度器:
SELECT EVENT_NAME, EVENT_DEFINITION FROM information_schema.EVENTS WHERE EVENT_DEFINITION LIKE '%CALL%';
关键细节:
- 触发器里的
CALL会以触发者身份执行,USER/HOST显示的是 DML 操作发起方,不是触发器创建者 -
EVENT默认用DEFINER权限运行,PROCESSLIST中看到的USER是定义者,不是调度器本身 - 如果
event_scheduler关闭(SELECT @@event_scheduler返回OFF),这类调用根本不会发生
CALL + 触发器兜底 + 定时事件补漏。只盯一个入口,大概率漏掉关键链路。











