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

Sql server 如何在TSQL中刷新打印缓冲区?,sql-server,tsql,printing,Sql Server,Tsql,Printing,我在SQLServer2005中有一个运行时间很长的存储过程,我正在尝试调试它,并使用“print”命令进行调试。问题是,我只在存储过程的最后从SQL Server获取消息—我希望能够刷新消息缓冲区,并在存储过程的运行时立即查看这些消息,而不是在存储过程的最后查看这些消息。使用以下函数: RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT 你不应该用错误完全替换你所有的指纹。如果你在某个地方有一个循环或者一

我在SQLServer2005中有一个运行时间很长的存储过程,我正在尝试调试它,并使用“print”命令进行调试。问题是,我只在存储过程的最后从SQL Server获取消息—我希望能够刷新消息缓冲区,并在存储过程的运行时立即查看这些消息,而不是在存储过程的最后查看这些消息。

使用以下函数:

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT
你不应该用错误完全替换你所有的指纹。如果你在某个地方有一个循环或者一个大的光标,那么每次迭代或者几次迭代就做一次或者两次

也是:我第一次在这个链接中了解了RAISERROR,我现在认为它是SQL Server错误处理的最终来源,绝对值得一读:


是的。。。RAISERROR函数的第一个参数需要一个NVARCHAR变量。因此,尝试以下方法

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

仅供参考,如果您在脚本批处理中工作,而不是在存储过程中工作,则刷新输出由GO命令触发,例如

print 'test'
print 'test'
go
一般来说,我的结论如下:mssql脚本执行的输出,在SMS GUI或sqlcmd.exe中执行,会刷新到文件、stdoutput、GUI窗口上的first GO语句或直到脚本结束

刷新存储过程内部的功能不同,因为您不能将其放入内部


参考:

另一个更好的选择是不依赖于PRINT或RAISERROR,只需将PRINT语句加载到TempDB中的Temp表或数据库中的永久表中,即可通过另一个窗口中的SELECT语句立即查看数据。这对我最合适。然后,使用一个永久表也可以作为记录过去发生的事情的日志。打印语句对于错误非常方便,但是使用日志表,您还可以根据该特定执行的上次记录值确定确切的故障点,前提是您跟踪日志表中的总体执行开始时间

基于@JoelCoehoorn的答案,我的方法是保留所有PRINT语句,并简单地使用RAISERROR语句跟随它们以引起刷新

例如:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT
这种方法的优点是PRINT语句可以连接字符串,而RAISERROR不能。因此,无论哪种方式,您都有相同数量的代码行,因为您必须声明并设置一个变量以在RAISERROR中使用

如果像我一样使用AutoHotKey或SSMSBoost或等效工具,则可以轻松设置快捷方式(如]flush)为您输入RAISERROR行。如果每次都是同一行代码,也就是说,不需要自定义以保存特定文本或变量,则可以节省时间。

要扩展,以下是正确使用表格方法的方法:

首先,如果sp使用事务,您将无法实时监视表的内容,除非您使用“读取未提交”选项:

要解决回滚问题,请在日志表上增加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
请注意以下重要细节:

将XACT_中止设置为OFF;防止SQL Server只是关闭整个事务而不是运行catch块,如果使用此技术,请始终包含它。 使用@table_变量,而不是temp_表。临时表也会受到回滚的影响。
查看底部“结果”选项卡旁边的“消息”选项卡或切换到“结果到文本”模式。要切换到“结果到文本”模式,请在SSMS中的“菜单工具”->“选项”->“查询结果”->“SQL Server”->“常规”->“结果的默认目标”,然后选择“结果到文本”而不是“结果到网格”,重新打开“查询”窗口后,当RAISERROR输出转到“消息”选项卡时,您将不会像坐在那里一样看着空白的“结果”选项卡。请注意,SQL中的TRY/CATCH只会捕获严重性>10的错误,因此以这种方式使用RAISERROR不会跳转到CATCH语句中。这很好,因为这意味着您仍然可以在TRY/CATCH中使用像这样的RAISERROR。ref:注意,这在前500条消息之后不起作用;一旦你打印了超过这个数字,它就会突然开始缓冲@MahmoudMoravej不,我仍然在使用RAISEERROR运行长时间运行的进程,只是在处理一段时间后,消息开始被缓冲的事实。看来唯一的解决办法是使用不同于SSMS的工具。我认为这在最近版本的SS中有所改变。早在我第一次写这篇文章的时候,我们就使用RAISERROR对500多条消息的隔夜批处理过程进行了广泛的日志记录,这并不是一个问题。但是在@GendoIkari的通知下,7年内会有很多变化。我用这个脚本从2016SP1开始用ssms进行了尝试。在500时,它切换到缓冲50行,在1k时,它切换到每行100行。这至少持续到2k,但后来我停止了脚本。声明@i int set@i=0声明@t varchar100,而1=1开始设置@i=@i+
SELECT *
FROM table_log WITH (READUNCOMMITTED);
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT *
FROM table_log;
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