应查询 sys.dm_exec_requests 视图筛选 command 为 'EXECUTE' 或 'RPC' 且 status 为 'running'/'suspended' 的记录,并联查 sys.dm_exec_sessions 排除系统会话,以准确定位正在执行的存储过程实例。

查 sys.dm_exec_requests 看 EXECUTE 命令状态
直接找正在跑的存储过程调用,别去查名字是否“存在”。SQL Server 不维护“某个 proc 是否在运行”的全局标记,所有运行态都体现在 sys.dm_exec_requests 里。
关键点是过滤 command = 'EXECUTE' 或 'RPC',且 status 为 'running' 或 'suspended'——这才是真正在执行或等资源的实例。
- 必须 JOIN
sys.dm_exec_sessions排除系统会话(session_id ) - 用
CROSS APPLY sys.dm_exec_sql_text(sql_handle)提取实际调用语句,确认是不是你关心的那个 proc 名 - 避免只查
program_name,它可能被客户端伪造或截断
示例:
SELECT r.session_id, t.text, r.status, r.cpu_time, r.logical_reads
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.command IN ('EXECUTE', 'RPC')
AND r.status IN ('running', 'suspended')
AND t.text LIKE '%YourProcName%';用 OBJECT_ID + session_id 关联更精准
靠模糊匹配 text 容易误判,尤其当 proc 名是通用词(如 usp_Update)或被动态拼接时。更稳的方式是通过对象 ID 反向定位。
sys.dm_exec_requests 没有直接暴露 proc 对象 ID,但 sys.dm_exec_query_stats 和 sys.dm_exec_procedure_stats 可以补上这一环。
- 先查
OBJECT_ID('YourProcName')得到 id - 再查
sys.dm_exec_procedure_stats中object_id匹配且last_execution_time在最近几秒内的记录,说明刚被调起 - 结合
sys.dm_exec_requests中sql_handle关联到该 proc 的当前执行上下文
注意:如果 proc 内部用了 EXEC(@sql) 或大量动态 SQL,对象 ID 可能无法全程保留,这时只能退回到文本匹配+人工核对。
为什么不能查 sys.dm_exec_cached_plans?
缓存计划里确实有 proc 的执行计划,但 sys.dm_exec_cached_plans 只表示“这个 proc 曾编译过”,不代表“正在运行”。哪怕 plan 还在缓存里,proc 也可能早已退出。
常见误操作是写:
SELECT * FROM sys.dm_exec_cached_plans p CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) t WHERE t.text LIKE '%YourProcName%';
这只会返回缓存中的计划碎片,和并发运行毫无关系。真正要监控“是否正在跑”,必须盯住 requests 视图,而不是 cached_plans。
另外,sys.dm_exec_procedure_stats 的 execution_count 是累计值,也不能反映瞬时并发数。
并发冲突时容易忽略的端点问题
判断“是否正在运行”常被用于实现互斥逻辑(比如禁止同一 proc 同时跑两次),但仅靠查 requests 有时间窗口漏洞:查询执行完到新实例启动之间存在间隙。
真正可靠的互斥必须靠数据库原语,例如:
- 用
sp_getapplock在 proc 开头加应用级锁,超时设为 0 实现立即失败 - 用带唯一约束的控制表(
INSERT ... SELECT+NOT EXISTS)做抢占式登记 - 避免用轮询查
requests再决定是否启动——竞态条件无法消除
单纯“判断是否在运行”只是诊断手段;想阻止并发,得换机制,不是换查询语句。

















