直接查 sys.dm_exec_requests 可判断 delete 是否运行中、卡在何处或被阻塞;dbcc opentran 定位事务起点;sys.dm_tran_locks 识别锁冲突;sp_whoisactive 提供完整执行上下文,核心是区分“慢”与“堵”。

直接查 sys.dm_exec_requests 看运行时状态
长事务 DELETE 本身不会暴露“已删多少行”这种进度值,但能从执行上下文中提取关键线索:是否还在运行、卡在哪、有没有被阻塞。最直接的方式是查 sys.dm_exec_requests,它反映当前所有活跃请求的实时快照。
重点关注这几个字段:command(应为 DELETE)、status(必须是 running 或 suspended)、wait_type(如 LCK_M_U 表示在等更新锁)、percent_complete(仅对某些操作如备份/还原有效,DELETE 永远为 0)。
-
session_id和request_id是定位该 DELETE 的唯一标识 - 若
status = 'suspended'且wait_type非空,说明它正被锁或 I/O 卡住,不是慢,是堵住了 -
start_time和last_wait_type结合看,能判断是否长时间停在同一个等待上
用 DBCC OPENTRAN 找最早未提交的事务起点
DBCC OPENTRAN 不显示进度,但它能告诉你这个长事务最早是从什么时候开始的——也就是事务 BEGIN 的时间点。这对判断“它是不是真卡住”很关键:如果事务已运行 45 分钟,但 DBCC OPENTRAN 显示它始于 2 分钟前,那大概率是刚启动就被阻塞了,而不是 DELETE 本身慢。
- 只在目标数据库上下文中执行,例如
USE [YourDB]; DBCC OPENTRAN; - 输出中的
Oldest active transaction行里的SPID可以和sys.dm_exec_requests中的session_id对应 - 若返回 “No active open transactions”,说明事务已回滚或提交,但你看到的可能是残留会话或连接池未释放
结合 sys.dm_tran_locks 看它锁了什么、被谁锁
DELETE 长时间不动,90% 是锁冲突导致。查 sys.dm_tran_locks 能看出它当前持有的锁(比如对某张表的 KEY 锁),以及它正在等待哪个资源(resource_description 字段常含页号或键值)。
- 先用
request_session_id过滤出该 DELETE 的锁记录 - 再查
resource_type = 'OBJECT'或'KEY',看它是否在逐行加锁(大量KEY锁说明没走索引或扫描范围过大) - 若发现
request_status = 'WAIT',往上翻找相同resource_description且request_status = 'GRANT'的记录,就能定位持锁者
别信 sp_who2,改用 sp_WhoIsActive
sp_who2 输出太简陋,不带 SQL 文本、不带等待资源细节、默认混入系统进程,容易漏掉关键信息。而 sp_WhoIsActive(需手动安装)默认就包含 sql_text、blocking_session_id、wait_info、tran_log_writes 等字段,一行就能判断 DELETE 是否在写日志、写了多少、被谁挡着。
- 执行
EXEC sp_WhoIsActive @get_outer_command = 1, @get_plans = 0;就够用 -
tran_log_writes值持续上涨,说明 DELETE 确实在推进;若长时间不变,基本就是卡死 - 注意
is_truncated字段:若为 1,说明sql_text被截断,得配合session_id去sys.dm_exec_sql_text手动查完整语句
真正难的不是查进度,而是区分“慢”和“堵”——前者要优化语句或加索引,后者要 kill 持锁者或调整事务边界。所有监控手段都只是帮你快速归因,别指望数据库自动告诉你“还剩 32768 行”。











