如何在TSQL中刷新打印缓冲区?

我在SQL Server 2005中有一个非常长时间运行的存储过程,我正在尝试调试,我正在使用'print'命令来执行它。问题是,我只是在我的sproc的最后从SQL Server得到消息-我希望能够在sproc的运行时期间立即刷新消息缓冲区并看到这些消息,而不是在最后。

113255 次浏览

使用RAISERROR函数:

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT

你不应该完全用raiserror替换你所有的打印。如果你有一个循环或者某个地方有一个大的游标,每次迭代只做一两次,甚至每几次迭代都做一次。

另外:我第一次在这个链接上了解了RAISERROR,我现在认为这是SQL Server错误处理的权威来源,绝对值得一读:
http://www.sommarskog.se/error-handling-I.html < / p >

是的……RAISERROR函数的第一个参数需要一个NVARCHAR变量。所以试试下面的方法吧;

-- Replace PRINT function
DECLARE @strMsg NVARCHAR(100)
SELECT @strMsg = 'Here''s your message...'
RAISERROR (@strMsg, 0, 1) WITH NOWAIT

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT

仅供参考,如果您使用脚本(批处理),而不是存储过程,刷新输出是由GO命令触发的,例如:

print 'test'
print 'test'
go

总的来说,我的结论如下:mssql脚本执行的输出,在SMS GUI或sqlcmd.exe中执行,在第一个GO语句或直到脚本结束时被刷新到文件,stdoutput, GUI窗口。

存储过程内部的刷新功能不同,因为您不能将GO放在存储过程内部。

参考:tsql Go语句

另一个更好的选择是不依赖PRINT或RAISERROR,只需将“PRINT”语句加载到TempDB中的##Temp表或数据库中的永久表中,这将使您立即通过另一个窗口的SELECT语句查看数据。这对我来说是最好的。使用永久表还可以作为记录过去发生的事情的日志。打印语句对于错误来说很方便,但是使用日志表,您还可以根据特定执行的最后记录值确定准确的故障点(假设您在日志表中跟踪总体执行开始时间)。

根据@JoelCoehoorn的回答,我的方法是保留所有的PRINT语句,然后简单地在它们后面加上RAISERROR语句来引起flush。

例如:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT

这种方法的优点是PRINT语句可以连接字符串,而RAISERROR不能。(所以无论哪种方式,你都有相同的代码行数,因为你必须声明和设置一个变量来在RAISERROR中使用)。

如果像我一样,你使用AutoHotKey或SSMSBoost或等效的工具,你可以很容易地设置一个快捷键,如“]flush”,为你进入RAISERROR行。如果每次都是同一行代码,这可以节省时间,也就是说,不需要定制以保存特定的文本或变量。

要扩展埃里克·艾萨克的回答,下面是如何正确使用表方法:

首先,如果你的sp使用事务,你将无法实时监控表的内容,除非你使用READ UNCOMMITTED选项:

SELECT *
FROM table_log WITH (READUNCOMMITTED);

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT *
FROM table_log;

为了解决回滚问题,在日志表中添加一个不断增加的ID,并使用以下代码:

SET XACT_ABORT OFF;
BEGIN TRY
BEGIN TRANSACTION mytran;
-- already committed logs are not affected by a potential rollback
-- so only save logs created in this transaction
DECLARE @max_log_id = (SELECT MAX(ID) FROM table_log);
/*
* do stuff, log the stuff
*/


COMMIT TRANSACTION mytran;
END TRY
BEGIN CATCH
DECLARE @log_table_saverollback TABLE
(
ID INT,
Msg NVARCHAR(1024),
LogTime DATETIME
);
  

INSERT INTO @log_table_saverollback(ID, Msg, LogTime)
SELECT ID, Msg, LogTime
FROM table_log
WHERE ID > @max_log_id;


ROLLBACK TRANSACTION mytran; -- this deletes new log entries from the log table


SET IDENTITY_INSERT table_log ON;


INSERT INTO table_log(ID, Msg, LogTime)
SELECT ID, Msg, LogTime
FROM @log_table_saverollback;


SET IDENTITY_INSERT table_log OFF;
END CATCH

注意这些重要的细节:

  1. SET XACT_ABORT OFF;可以防止SQL Server关闭整个事务,而不是运行catch块,如果你使用这种技术,一定要包括它。
  2. 使用@table_variable,而不是#temp_table。临时表也会受到回滚的影响。