2010-05-30 144 views
20

如果你有一个长时间运行的SP,你记录它的行为或只是等待这个消息?最佳实践 - 存储过程记录

“命令已成功完成”。

我认为,在这个问题上可以有很多解决方案,但有没有最佳实践 - 一个经常使用的简单解决方案?

编辑

我发现在这个问题上

http://weblogs.sqlteam.com/brettk/archive/2006/09/21/12391.aspx

本文介绍使用日志表一个有趣的联系,但有一个问题

的记录过程必须在任何交易之外执行

由于我使用了光标,因此我无法在外部调用该插入,并且在每行上的该表中插入一行。

任何想法?

EDIT 2

挖..

有SQL Server中的xp_logevent。你试过了吗?

SQL Server Profiler

还有Creating Log file for Stored Procedure

+0

定义长时间运行? – 2010-05-30 09:48:18

+0

任何sp,不止是一对选择和更新。例如,如果您使用光标,并且需要观察进度。我的问题有什么不对吗? – hgulyan 2010-05-30 09:55:21

回答

22

你是如何调用存储过程的?如果是通过Management Studio中,那么你可以很容易地打印出信息如下

RAISERROR ('Some debugging info', 0, 1) WITH NOWAIT 

这是优于使用PRINT作为消息会立即出现。通过为Connection.InfoMessage事件配置一个处理程序,也可以在ADO.NET中捕获这些消息。

我看到您已经列出了SQL Profiler作为一种可能性。您可能有兴趣知道您可以在SQL Profiler中看到log your own user configurable events

+1

我在管理工作室中调用sp,但问题是一般的,所以如果有一种很好的日志记录方式,它也可以在应用程序中使用。 我不需要RAISERROR,因为我需要记录进程,而不是错误。打印可以是一个选项,但如果sp打印每秒1000行? 我已经试过了SQL Profiler。这是一个不错的选择,但它不是一个真正的日志。这是更多的监测,我想,剖析器不是一个通用的解决方案。 也许解决方案将所有这些告诉了这里。 – hgulyan 2010-05-30 14:56:20

+1

不要被名字混淆RAISERROR不仅仅是因为错误。严重性小于10的任何信息仅用于信息消息。显然,无论您使用哪种日志框架,都需要对其进行设计,以便记录适量的信息。 – 2010-05-30 15:03:38

+0

Raiserror会不会停止sp? p.s.并感谢您在Profiler中定制用户配置。感谢这个话题中最有趣的链接。 – hgulyan 2010-05-30 15:05:26

3

我们通常使用记录表,围着交易服务。我们几乎可以避免任何涉及到SQL Server以外的任何事情(例如写入文件系统,调用外部服务,.NET程序集等)。

我们也尝试避免游标 - 是否有可能您的proc长时间运行,因为它效率低下?

+0

你能更具体吗? 如果您无法在事务外插入日志表,该怎么办? 我知道,不建议使用游标,但它是一次性使用脚本,并且没有其他方法,所以在需要使用游标时就是这种情况。 – hgulyan 2010-05-30 14:51:17

7

为了看看事情要花多长时间,以及上一个操作修改了多少行,我将当前日期+时间和最后一行计数添加到每个条目。我用这个方法:

CREATE PROCEDURE dbo.[Log] 
    @Message NVARCHAR(512), 
    @RowCount INT = null OUTPUT, 
    @Delimiter NCHAR(1) = N' ', 
    @PadChar NCHAR(1) = N'-' 
AS 
    BEGIN 
     SET @RowCount = @@ROWCOUNT; 

     DECLARE @LogDate AS NVARCHAR(50); 
     DECLARE @RowCountPadded AS NCHAR(8); 

     SET @LogDate = CONVERT(NVARCHAR(50),GETDATE(),121); 
     SELECT @RowCountPadded = CASE @RowCount WHEN 0 THEN REPLICATE(@PadChar,8) ELSE REPLACE(STR(@RowCount, 8), SPACE(1), @PadChar) END; 

     SET @Message = @LogDate + @Delimiter + @RowCountPadded + @Delimiter + @Message; 
     RAISERROR (@Message, 0, 1) WITH NOWAIT; 
    END 

所以,在你的程序中,添加日志输出是这样的:

EXEC dbo.[Log] 'the message'; 

它产生这样的:

2012-12-28 11:28:25.197 -------- the message 

假如您以前执行一些动作,你看到破折号的行数。如果您需要行数(例如记录到表),则可以从过程中将其作为OUTPUT参数返回。

UPDATE如果您想创建此过程一次并在任何地方使用,请使用此gist

0

我用这个程序

CREATE PROCEDURE dbo.PrintLog (
    @Msg VARCHAR(2048) 
    , @Option VARCHAR(100) = '' 
    , @Separator VARCHAR(10) = '-' 
    ) 
/* 
@Option is a string containing possible values as B,A,D,T 
if you want to print separator before message, include B 
if you want to print separator after message, include A 
if you want to print date, include D 
if you want to print time, include T 
Sample: 'BAD' 

The order of characters does not matter. it is not case sensitive 

Usage: 
    exec dbo.PrintLog 'Timed Log', 'T' 
    exec dbo.PrintLog 'Dated Log', 'D' 
    exec dbo.PrintLog 'With Separator and Time', 'BT', '><' 
    exec dbo.PrintLog 'With Separator and Date', 'BAD', '*' 
    exec dbo.PrintLog 'With Separator and DateTime', 'BADT', 'x' 
*/ 
AS 
BEGIN 
    declare @tempStr varchar(100) 
    set @tempStr = replicate(@Separator, 50) 
    IF charindex('B', upper(@Option)) > 0 
     raiserror (@tempStr, 10, 1) with nowait 

    DECLARE @prompt VARCHAR(max) = '' 

    IF charindex('D', upper(@Option)) > 0 
     SET @prompt = convert(VARCHAR, SysDatetime(), 101) + ' ' 

    IF charindex('T', upper(@Option)) > 0 
     SET @prompt = @prompt + convert(VARCHAR, SysDatetime(), 108) + ' ' 
    SET @prompt = @prompt + @Msg 

    raiserror (@prompt, 10, 1) with nowait 

    set @tempStr = replicate(@Separator, 50) 
    IF charindex('A', upper(@Option)) > 0 
     raiserror (@tempStr, 10, 1) with nowait 

    RETURN 
END 

GO 

使用

exec dbo.PrintLog 'Date and Timed Log', 'DT' 
    exec dbo.PrintLog 'Dated Log', 'D' 
    exec dbo.PrintLog 'With Separator and Time', 'BT', '><' 
    exec dbo.PrintLog 'With Separator and Date', 'BAD', '*' 
    exec dbo.PrintLog 'With Separator and DateTime', 'BADT', 'x' 

到你想要的值,您还可以更改参数默认。