SQL Server原生不提供UPDATE进度百分比,唯一实时输出进展的方式是RAISERROR WITH NOWAIT;需满足severity 0–10、WITH NOWAIT、消息≤2048字符,且.NET需监听InfoMessage事件、SSMS需启用实时结果选项。

SQL Server 原生不提供 UPDATE 进度百分比,但可通过 RAISERROR WITH NOWAIT 实时输出行数进展——这是唯一绕过缓冲、立刻送达客户端的方式。
为什么 SELECT @@ROWCOUNT 或 sys.dm_exec_requests 不够用
执行中的 UPDATE 语句在 sys.dm_exec_requests 里状态是 running,但 percent_complete 字段对普通 DML(包括 UPDATE)始终为 0;@@ROWCOUNT 只返回上一条语句影响的行数,无法反映“已处理多少/总共多少”。想靠轮询 sys.dm_exec_sql_text 看 SQL 文本变化?它不会动态更新进度。真正能用的,只有主动“打点”。
用 RAISERROR WITH NOWAIT 打进度日志
必须满足三个条件才能实时看到:显式指定 severity 0–10、加上 WITH NOWAIT、确保消息长度 ≤2048 字符。示例片段:
DECLARE @done INT = 0, @total INT = 100000;
WHILE @done < @total
BEGIN
UPDATE TOP (1000) t
SET status = 'processed'
FROM orders t
WHERE status = 'pending' AND id > @done;
<pre class='brush:php;toolbar:false;'>SET @done += @@ROWCOUNT;
RAISERROR(N'已完成 %d/%d 行', 0, 1, @done, @total) WITH NOWAIT;
WAITFOR DELAY '00:00:00.01'; -- 避免刷屏过快END
-
RAISERROR的 severity 必须是 0–10,否则会被缓冲 - 数字变量必须用
%d占位,不能拼接字符串(CONCAT或+会触发隐式转换失败) - .NET 客户端默认丢弃这类消息,需设置
SqlConnection.InfoMessage事件监听 - SSMS 中需勾选“查询”→“查询选项”→“结果”→“将结果发送到网格”时启用“在执行期间显示实时结果”
避免踩坑:上线前必须清理或禁用
每调用一次 RAISERROR WITH NOWAIT 都有网络往返开销。实测在循环中每 100 行打一次,性能下降约 5%;若每行都打,延迟飙升 30%+。更危险的是:如果消息里含 NULL 值且未用 ISNULL(@var, N'') 处理,整个批处理会中断。生产环境务必把所有 RAISERROR 行注释掉,或用 IF @debug = 1 BEGIN ... END 包裹。
真正难的是预估总行数——COUNT(*) 加锁又慢,而 sys.dm_db_partition_stats 的 row_count 是近似值。所以进度条本质是“趋势参考”,不是精确仪表盘。

















