我在SQL Server 2005中有一个非常长时间运行的存储过程,我正在尝试调试,我正在使用'print'命令来执行它。问题是,我只是在我的sproc的最后从SQL Server得到消息-我希望能够在sproc的运行时期间立即刷新消息缓冲区并看到这些消息,而不是在最后。
使用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
是的……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
仅供参考,如果您在脚本(批处理)中工作,而不是在存储过程中,刷新输出是由GO命令触发的,例如。
print 'test'
print 'test'
go
总的来说,我的结论如下:mssql脚本执行的输出,在SMS GUI或sqlcmd.exe中执行,在第一个GO语句或直到脚本结束时被刷新到文件,stdoutput, GUI窗口。
存储过程内部的刷新功能不同,因为您不能将GO放在存储过程内部。
参考:tsql Go语句
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.)
根据@JoelCoehoorn的回答,我的方法是保留所有的PRINT语句,然后简单地在它们后面加上RAISERROR语句来引起flush。
例如:
PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT
这种方法的优点是PRINT语句可以连接字符串,而RAISERROR不能。(所以无论哪种方式,你都有相同的代码行数,因为你必须声明和设置一个变量来在RAISERROR中使用)。
如果像我一样,你使用AutoHotKey或SSMSBoost或等效的工具,你可以很容易地设置一个快捷键,如“]flush”,为你进入RAISERROR行。如果每次都是同一行代码,这可以节省时间,也就是说,不需要定制以保存特定的文本或变量。
为了扩展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。临时表也会受到回滚的影响。
推荐文章
- SQL Server:过滤sp_who2的输出
- 在SQL Server上使用varchar(MAX) vs TEXT
- Visual Studio: ContextSwitchDeadlock
- Sql Server字符串到日期的转换
- 如何将SQL Azure数据库复制到本地开发服务器?
- SQL Server 2008不能用新创建的用户登录
- SQL Server中User和Login的区别
- 在参数声明中,varchar(MAX)的大小是多少?
- 数据库性能调优有哪些资源?
- 为两列的组合添加唯一的约束
- SQL Server的隐藏特性
- 方括号[]在sql语句中有什么用?
- 对象'DF__*'依赖于列'*' -将int改为double
- 如何根据出生日期和getDate()计算年龄(以年为单位)
- 最有效的T-SQL方法垫一个varchar的左边到一定的长度?