245

我正在尝试调试 SQL Server 2005 中有一个运行时间很长的存储过程,并且我正在使用“打印”命令来执行此操作。问题是,我只是在存储过程的最后从 SQL Server 获取消息 - 我希望能够在存储过程的运行时刷新消息缓冲区并立即查看这些消息,而不是在结尾。

4

6 回答 6

333

使用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

于 2008-11-20T21:58:02.360 回答
46

基于@JoelCoehoorn 的回答,我的方法是将我的所有 PRINT 语句保留在原位,然后简单地使用 RAISERROR 语句跟随它们以导致刷新。

例如:

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

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

如果像我一样,您使用 AutoHotKey 或 SSMSBoost 或等效工具,您可以轻松设置快捷方式,例如“]flush”为您输入 RAISERROR 行。如果每次都是同一行代码,这可以节省您的时间,即不需要定制来保存特定的文本或变量。

于 2017-09-11T00:51:18.410 回答
20

是的... 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
于 2010-11-01T10:32:01.657 回答
13

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

于 2016-04-18T20:43:35.527 回答
5

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

print 'test'
print 'test'
go

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

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

参考:tsql Go 语句

于 2015-05-23T17:24:22.503 回答
1

为了扩展Eric Isaac 的答案,这里是如何正确使用表格方法:

首先,如果您的 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。临时表也受到回滚的影响。
于 2021-05-18T10:21:04.953 回答