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


当前回答

Another better option is to not depend on PRINT or RAISERROR and just load your "print" statements into a ##Temp table in TempDB or a permanent table in your database which will give you visibility to the data immediately via a SELECT statement from another window. This works the best for me. Using a permanent table then also serves as a log to what happened in the past. The print statements are handy for errors, but using the log table you can also determine the exact point of failure based on the last logged value for that particular execution (assuming you track the overall execution start time in your log table.)

其他回答

Another better option is to not depend on PRINT or RAISERROR and just load your "print" statements into a ##Temp table in TempDB or a permanent table in your database which will give you visibility to the data immediately via a SELECT statement from another window. This works the best for me. Using a permanent table then also serves as a log to what happened in the past. The print statements are handy for errors, but using the log table you can also determine the exact point of failure based on the last logged value for that particular execution (assuming you track the overall execution start time in your log table.)

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

print 'test'
print 'test'
go

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

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

参考:tsql Go语句

为了扩展Eric Isaac的回答,以下是如何正确使用表格方法:

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

SELECT *
FROM table_log WITH (READUNCOMMITTED);

or

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

注意这些重要的细节:

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

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

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

OR

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

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