WAITFOR DELAY 和 PRINT 语句

WAITFOR DELAY and PRINT statement

提问人:Tax Max 提问时间:7/11/2023 更新时间:10/12/2023 访问量:196

问:

我有一个简单的while循环:

DECLARE @Counter INT 

SET @Counter = 1

WHILE (@Counter <= 10)

BEGIN

    PRINT 'The counter value is = ' + CONVERT(VARCHAR,@Counter) WAITFOR DELAY '00:00:01'
    SET @Counter  = @Counter  + 1
    
END

我希望@counter值将以 1 秒的延迟打印出来,但相反,代码在 10 秒后执行,结果在执行结束时一次性打印出来。

The counter value is = 1
The counter value is = 2
The counter value is = 3
The counter value is = 4
The counter value is = 5
The counter value is = 6
The counter value is = 7
The counter value is = 8
The counter value is = 9
The counter value is = 10

如何确保每个下一个值都以 1 秒的延迟打印出来,以便我可以监控进度?

只是一些背景。我想使用类似的脚本来监视备份和还原进度。 例如,将进度百分比的初始值分配给:

SELECT @Counter = percent_complete
FROM sys.dm_exec_requests r 
   CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) a 
WHERE r.command in ('BACKUP DATABASE','RESTORE DATABASE');

并每 5 秒监控一次 while 循环中的进度percent_complete直到达到 100%。

sql-server while-loop 睡眠

评论

8赞 Dai 7/11/2023
“如何确保每个下一个值都以 1 秒的延迟打印出来,以便我可以监控进度?”- 你不能:相反,你应该使用 RAISERROR (sic) 而不是 - 这样你的客户端就会立即获得状态消息。此外,完全是一个单独的语句,而不是 的修饰符。NOWAITWAITFORWAITFORPRINT
0赞 Dai 7/11/2023
“只是一些背景。我想使用类似的脚本来监视备份和还原进度。例如,将进度百分比的初始值分配给:“ - 这不是将备份/恢复进度信息传递给 TDS 客户端的最佳方法 (imo):请考虑改用 XEvents
0赞 Panagiotis Kanavos 7/11/2023
您不能像这样报告备份进度。无论如何,实际进度已经发送到控制台。我建议使用 Ola Hallengen 的备份和还原脚本,而不是滚动自己的脚本。这些脚本处理多个数据库和对表的日志记录操作。如果检查脚本,你会看到使用了脚本,而不是立即将结果返回给调用方。SELECTPRINT
0赞 Charlieface 7/11/2023
@Dai 可以使用并从消息中获取它WITH STATS = 1

答:

1赞 Stu 7/11/2023 #1

除了注释中已有的建议之外,请尝试使用此修改后的脚本来演示如何使用 raiserror 来执行示例代码中预期的行为。

请记住选择“消息”(Messages) 表格以查看输出。

declare @Counter Int = 1;

while (@Counter <= 10)
begin
  raiserror ('The counter value is %d', 0, 1, @Counter) with nowait;
  waitfor delay '00:00:01';
  set @Counter += 1;
end;

评论

0赞 Tax Max 7/11/2023
谢谢你提供这个例子。它在 SQL Server Management Studio 中工作正常,但不能在 .它在后台执行脚本 10 秒钟,完成后显示在输出中 - 同时显示所有行。SQLCMDThe counter value is 1 <...> The counter value is 10
1赞 Stu 7/12/2023
我不相信sqlcmd以相同的方式处理输出。但是,MS 还发布了一个名为 Go-sqlcmd 的更新版本,我没有使用过它,但您可以尝试一下。
0赞 Tax Max 7/13/2023
谢谢你!不知道它的存在。我会试一试。
0赞 Charlieface 7/11/2023 #2

你说

我想使用类似的脚本来监视备份和还原进度

完全不要使用此循环。只需使用 STATS 选项,您可以在其中指定百分比更改以显示更新。这是所有备份工具用来监视进度的方法。

BACKUP DATABASE
......
WITH STATS = 1;

评论

0赞 Tax Max 7/11/2023
谢谢。就我而言,我指定了 STATS 选项,但百分比显示在备份结束时,但在备份操作正在进行时不显示。SQLCMD -SDB_HOST -Q “将数据库 [MY_DB] 备份到磁盘 = 'C:\TEMP\MY_DB.bak' 格式,统计信息 = 10;”10% 已处理。20% 已处理。<...> 90% 已处理。处理了数据库“MY_DB”的466152页,文件“MY_DB_data”在文件 1 上。100%处理。
0赞 Charlieface 7/11/2023
可能是 sqlcmd 在命令完成之前不显示它。在 SSMS 中尝试它应该可以工作。
0赞 Tax Max 7/11/2023
看来你是对的。刚刚找到一个答案,指出“我相信 SQLCMD 是针对 2012 年重写的,这样打印语句,甚至在通过 SQLCMD 运行期间发出的 raierror 消息在整个作业完成之前都不会显示。
0赞 Charlieface 7/11/2023
如果使用该选项会发生什么情况-j
0赞 Tax Max 7/11/2023
结果仅在最后显示,并附有其他信息:[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]The counter value is 1 [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]The counter value is 2 [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]The counter value is 3 [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]The counter value is 4
0赞 Tax Max 7/11/2023 #3

如何使用 sqlcmd 在批处理文件中显示进度?中提到了一种解决方案。其他解决方案是使用 Powershell。

GO
CREATE PROCEDURE [scutility].[SqlCmdTestOutput]
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @count INT = 50
    DECLARE @msg VARCHAR(8000)

    WHILE @count > 0
    BEGIN
        SET @msg = convert(VARCHAR(50), sysdatetime())

        RAISERROR (@msg,0,1) WITH NOWAIT

        WAITFOR DELAY '00:00:10'

        SET @count -= 1
    END
END

若要调用此过程,请使用 Invoke-Sqlcmd。

powershell.exe -command "Invoke-Sqlcmd -ServerInstance '.' -Query '[scutility].[SqlCmdTestOutput]' -Database SCUTILITY -Verbose -QueryTimeout 0"

更多细节在这里 - https://dba.stackexchange.com/questions/222054/how-to-report-stats-on-restore-via-sqlcmd