直接查 sys.dm_exec_requests 是判断存储过程是否真在运行的最准方式,需结合 status(running/runnable/suspended)和 cross apply sys.dm_exec_sql_text(sql_handle) 匹配过程名,排除 sleeping 状态及系统会话,避免仅凭 command='execute' 误判。

怎么用 sys.dm_exec_requests 查存储过程是否真在跑
直接查 sys.dm_exec_requests 是判断“此刻是否正在执行”的最准方式,它反映的是当前 SQL Server 内存中真实活跃的请求,不是历史记录、也不是缓存快照。
关键点在于:不能只看 command = 'EXECUTE',必须结合 status 字段和实际 SQL 文本才能确认是不是你的目标存储过程正在跑。
-
status必须是running、runnable或suspended—— 这三种才代表“正占用资源执行中”;sleeping是连接空闲,哪怕刚执行完也显示这个,别误判 - 仅靠
command字段值为EXECUTE不够可靠,因为很多动态 SQL 或封装调用也会触发该值 - 必须用
CROSS APPLY sys.dm_exec_sql_text(sql_handle)拿到完整文本,再用LIKE匹配你的存储过程名(注意大小写和空格,建议用LOWER()统一处理) - 过滤掉系统会话:
session_id > 50,避免把内部维护线程混进来
为什么关联 sys.dm_exec_sql_text 后还看不到存储过程名
常见现象是查出来 text 字段只有 EXEC proc_name 或 EXEC @ret = proc_name,看不到里面具体干了什么。这不是 bug,是 SQL Server 的设计行为:
-
sys.dm_exec_sql_text返回的是“语句级”文本,不是“过程体”内容;存储过程被调用时,SQL Server 只缓存调用语句本身,不展开内部逻辑 - 如果你需要看到过程体内某一行(比如卡在某个 UPDATE),原生不支持——SQL Server 没有类似 MySQL 的
events_statements_current行级追踪能力 - 想定位内部卡点,只能靠加日志(如
PRINT或写入临时表)、或用扩展事件捕获sp_statement_starting事件(开销较大)
查不到结果的几个典型原因
执行了查询但返回空集,不代表存储过程没运行,可能只是没命中条件:
- 存储过程已执行完毕,但连接未关闭 → 状态是
sleeping,不在查询范围内 - 执行计划刚被清除(例如内存压力大、DBA 手动清缓存),
sql_handle失效 →sys.dm_exec_sql_text关联失败,整行被过滤掉 - 你用的是命名管道或本地连接,某些低权限账号无法读取
sys.dm_exec_sql_text→ 报错或返回空,需确认账号有VIEW SERVER STATE权限 - 存储过程里用了
WAITFOR DELAY或锁等待 → 状态可能是suspended,但wait_type显示WAITFOR或LCK_M_U,这是正常等待,不是异常卡死
生产环境轮询要注意什么
仪表盘或监控脚本如果每秒查一次 sys.dm_exec_requests,在 OLTP 高并发库上容易引发性能抖动:
- 最小轮询间隔建议 ≥ 5 秒;若只关注长任务,可设为 15–30 秒
- 务必加
WHERE command = 'EXECUTE',排除 SELECT/INSERT 等干扰项 - 不要 SELECT *,只取必要字段:
session_id、status、start_time、cpu_time、total_elapsed_time、text - 如果只查某一个存储过程,
LIKE条件要写紧,例如text LIKE '%[my_proc] %'(加方括号防名字被当关键字),避免全表扫描sys.dm_exec_sql_text返回的文本
真正难的不是查到“正在跑”,而是区分“跑得慢”和“卡死了”——前者看 total_elapsed_time 和 wait_type,后者得结合锁视图和执行计划分析。这点很容易被忽略,但线上问题往往卡在这一步。











