【问题标题】:SQL Alert when stored procedure executes for too long存储过程执行时间过长时发出 SQL 警报
【发布时间】:2009-02-23 10:59:08
【问题描述】:

我想设置一个 SQL Server 2008 警报,以便在任何过程执行 1 秒或更长时间时通知我(只是一个示例)。

有什么想法吗?

编辑:

好吧,看来这是不可能的。但是,只是为了让您转向另一个方向,我知道主数据库中有统计表,其中包含编译计数、调用次数和其他各种统计信息。我是否可以定期查询它们,然后以某种方式进行报告?

【问题讨论】:

    标签: sql-server sql-server-2008 monitoring notifications alert


    【解决方案1】:

    没有这方面的通知。 您必须设置跟踪并不时对其进行轮询。

    【讨论】:

    • 你能告诉我更多细节吗?
    【解决方案2】:

    我想补充 Mladen Prajdic 的正确答案,并改进来自 SQL Server Central 的 kevchadders 的答案。我在下面提出的解决方案使用 DBMail 而不是 SQLMail(SQLServerCentral 的解决方案通过 xp_sendmail 调用使用它)。本质上,SQLMail 使用 MAPI,更难设置,而 DBMail 使用 SMTP,更容易设置。这是more information关于两者之间的区别。

    我无法让 SQL Server Central 的解决方案在 SQL 2005 中运行,并且以下解决方案仅在我安装的 SQL 2005 - 基于版本的 YMMV 上进行了测试。

    首先,您需要一个新的 UDF,它将作业 ID 转换为 JOIN 的进程 ID:

    CREATE FUNCTION dbo.udf_SysJobs_GetProcessid(@job_id uniqueidentifier)
    RETURNS VARCHAR(8)
    AS
    BEGIN
        RETURN (substring(left(@job_id,8),7,2) +
        substring(left(@job_id,8),5,2) +
        substring(left(@job_id,8),3,2) +
        substring(left(@job_id,8),1,2))
    END
    

    然后是存储过程:

    CREATE PROC sp_check_job_running 
        @job_name char(50),
        @minutes_allowed int, 
        @person_to_notify varchar(50) 
    
    AS 
    
    DECLARE @minutes_running int, 
        @message_text varchar(255)
    
    SELECT @minutes_running = isnull(DATEDIFF(mi, p.last_batch, getdate()), 0)
    FROM master..sysprocesses p
    JOIN msdb..sysjobs j ON dbo.udf_sysjobs_getprocessid(j.job_id) = substring(p.program_name,32,8)
    WHERE j.name = @job_name
    
    IF @minutes_running > @minutes_allowed 
        BEGIN
          SELECT @message_text = ('Job ' + UPPER(SUBSTRING(@job_name,1,LEN(@job_name))) + ' has been running for ' + SUBSTRING(CAST(@minutes_running AS char(5)),1,LEN(CAST(@minutes_running AS char(5)))) + ' minutes, which is over the allowed run time of ' + SUBSTRING(CAST(@minutes_allowed AS char(5)),1,LEN(CAST(@minutes_allowed AS char(5)))) + ' minutes.') 
          EXEC msdb.dbo.sp_send_dbmail
            @recipients = @person_to_notify,
            @body = @message_text,
            @subject = 'Long-Running Job to Check' 
        END
    

    可以轻松地将这个存储过程安排为 SQL Server 代理作业或任何其他必要的方法。如果作业未运行或在指定参数内运行,则不执行任何操作。如果作业运行时间超过指定时间,它会发送电子邮件。

    例如

    EXEC sp_check_job_running 'JobNameGoesHere', 5, 'admin@mycompany.com'
    

    HT:http://www.sqlserverspecialists.co.uk/blog/_archives/2008/11/26/3996346.html

    【讨论】:

      【解决方案3】:

      如果在 sqlservercentral 上找到这个(可能是旧版本的 SQL Server,但仍然可能与 2008 年相关)

      长时间运行作业的警报程序 http://www.sqlservercentral.com/scripts/Lock+and+Connection+Management/30144/

      如果您无法访问,请在下方输入文字。

      对于定期运行且只需要很短时间运行的作业,DBA 可能想知道作业何时运行了过多时间。在这种情况下,仅检查作业是否正在运行是行不通的;需要确保它没有长时间运行的能力。将作业 ID 与 sysprocesses 中的进程 ID 匹配需要重新安排作业 ID 以进行匹配。此脚本创建一个存储过程,该过程将接受作业名称、允许的最长运行时间和要通知的电子邮件地址。然后它将使用作业名称重新排列作业编号并检查 sysprocesses(基于作为程序名称一部分的进程 ID)以确定作业运行的时间量,然后在该时间结束时发出警报“时间允许”参数。

      CREATE proc sp_check_job_running
          @job_name       char(50),
          @minutes_allowed    int,
          @person_to_notify   varchar(50)
      AS  
      
      DECLARE @var1           char(1),
          @process_id     char(8),
          @job_id_char        char(8),
          @minutes_running    int,
          @message_text       varchar(255)
      
      select @job_id_char = substring(CAST(job_id AS char(50)),1,8) 
      from  msdb..sysjobs
      where name = @job_name
      
      select @process_id =    substring(@job_id_char,7,2) + 
                  substring(@job_id_char,5,2) +
                  substring(@job_id_char,3,2) +
                  substring(@job_id_char,1,2)
      
      
      select @minutes_running = DATEDIFF(minute,last_batch, getdate())
      from master..sysprocesses
      where program_name LIKE ('%0x' + @process_id +'%')
      
      if @minutes_running > @minutes_allowed
        BEGIN
          select @message_text = ('Job ' 
          + UPPER(SUBSTRING(@job_name,1,LEN(@job_name)))
          + ' has been running for '
          + SUBSTRING(CAST(@minutes_running AS char(5)),1,LEN(CAST(@minutes_running AS char(5))))
          + ' minutes, which is over the allowed run time of '
          + SUBSTRING(CAST(@minutes_allowed AS char(5)),1,LEN(CAST(@minutes_allowed AS char(5)))) 
          + ' minutes.')
          EXEC master..xp_sendmail 
          @recipients = @person_to_notify, 
          @message = @message_text,
              @subject = 'Long-Running Job to Check'
        END
      
      --  Typical job step syntax for job to do the checking
      
      execute sp_check_job_running
            'JobThatSHouldBeDoneIn5Minutes', 
             5, 
             'DBAdmin@mycompany.com'
      

      【讨论】:

      • 这将检查工作绩效。我需要检查数据库(或整个服务器)中执行的每个存储过程。
      【解决方案4】:

      您可以使用Nagios 之类的监控软件定期统计数据库中慢查询的数量。

      我个人将以下查询与出色的PRTG 一起使用。我将其设置为每当我有超过 5 个执行时间大于 3 秒的查询时,或者当最慢的查询时间超过 10 秒时向我发送一封电子邮件:

      SELECT total_elapsed_time / execution_count / 1000000 avg_elapsed_time, execution_count, creation_time, last_execution_time, 
      SUBSTRING(st.text, (qs.statement_start_offset/2) + 1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) AS statement_text
      FROM sys.dm_exec_query_stats AS qs
      CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
      WHERE total_elapsed_time / execution_count / 1000000 >= 3  -- filter queries that takes > 3 seconds
      AND CHARINDEX('dm_exec_query_stats', st.text) = 0   -- In case this query is slow, we don't want it in the result set!
      ORDER BY total_elapsed_time / execution_count DESC;
      

      免责声明:此查询基于https://stackoverflow.com/a/820252/638040

      现在,如果您想监控您的存储过程,只需使用 sys.dm_exec_procedure_stats 而不是 sys.dm_exec_sql_text(同时从选择中删除字段 creation_time 并调整 st.text 上的 SUBSTRING)

      【讨论】:

        【解决方案5】:

        您可以使用 SQL Profiler 记录运行缓慢的查询,但具体而言,这不会帮助您发出警报。 (我想您可以登录到文件或数据库表,并让其他东西“监听”并发出警报)。

        如果您不熟悉 SQL Profiler,请按照以下步骤操作:

        您应该在服务器本身以外的其他东西上运行 SQL Profiler。

        从 SQLProfilerTSQL_Duration 模板开始

        设置过滤器:持续时间:“大于”为 1000(毫秒)

        如果需要,您可以在过滤器中限制数据库、登录或类似内容。

        在事件中,您可以限制为仅 SProcs(默认还包括 SQL 语句)

        【讨论】:

        • ServersAlive 之类的东西会做吗?它可以设置为针对 SQL Server 表运行查询,例如“过去 N 分钟内的任何新日志条目”。 ServersAlive 可以通过 SMTP、SMS、Pager 等发出警报。www.woodstone.nu/salive 我希望 SQL 代理可以做类似的事情。
        【解决方案6】:

        如果您不是在寻找免费的解决方案,您可以查看SQL Sentry。它可以满足您的要求以及更多功能。

        【讨论】:

          猜你喜欢
          • 2020-09-22
          • 1970-01-01
          • 2014-10-15
          • 2011-01-13
          • 1970-01-01
          • 1970-01-01
          • 2021-09-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多