AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 34313
Accepted
Lumpy
Lumpy
Asked: 2013-02-08 05:14:24 +0800 CST2013-02-08 05:14:24 +0800 CST 2013-02-08 05:14:24 +0800 CST

识别阻塞并发送警报

  • 772

我需要创建一个警报,当任何查询被阻止超过 60 秒时会通知我。例如,如果有人在表上打开了一个事务并且忘记运行提交或回滚。这可以从系统表中获得吗?

sql-server-2008-r2
  • 2 2 个回答
  • 11417 Views

2 个回答

  • Voted
  1. Best Answer
    db2
    2013-02-08T08:02:53+08:002013-02-08T08:02:53+08:00

    我喜欢 Martin 的使用事件通知的建议,所以我按照他的示例链接,将它放在一起用于我们的服务器。您需要将您的电子邮件地址放入对 sp_send_dbmail 的调用中,或者修改该过程以从某种配置表中读取电子邮件地址。此外,根据您的喜好调整阻止的进程阈值。结果是一条简明的报告消息,其中包含有关被阻止和阻止进程的信息。

    错误处理非常基础;如果收到错误消息或结束对话消息,它只会结束对话。

    确保在您的系统上配置数据库邮件以允许使用 sp_send_dbmail。

    USE msdb
    GO
    
    EXEC sp_configure 'show advanced options', 1
    RECONFIGURE
    GO
    EXEC sp_configure 'blocked process threshold', 30
    RECONFIGURE
    GO
    
    CREATE QUEUE BlockedProcessQueue
    
    CREATE SERVICE BlockedProcessService ON QUEUE BlockedProcessQueue ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification])
    GO
    
    USE master
    GO
    
    CREATE FUNCTION [dbo].[wait_resource_name](@obj nvarchar(max))
    RETURNS @wait_resource TABLE (
        wait_resource_database_name sysname,
        wait_resource_schema_name sysname,
        wait_resource_object_name sysname
    )
    AS
    BEGIN
        DECLARE @dbid int
        DECLARE @objid int
    
        IF @obj IS NULL RETURN
        IF @obj NOT LIKE 'OBJECT: %' RETURN
    
        SET @obj = SUBSTRING(@obj, 9, LEN(@obj) - 9 + CHARINDEX(':', @obj, 9))
    
        SET @dbid = LEFT(@obj, CHARINDEX(':', @obj, 1) - 1)
        SET @objid = SUBSTRING(@obj, CHARINDEX(':', @obj, 1) + 1, CHARINDEX(':', @obj, CHARINDEX(':', @obj, 1) + 1) - CHARINDEX(':', @obj, 1) - 1)
    
        INSERT INTO @wait_resource (wait_resource_database_name, wait_resource_schema_name, wait_resource_object_name)
        SELECT db_name(@dbid), object_schema_name(@objid, @dbid), object_name(@objid, @dbid)
    
        RETURN
    END
    GO
    
    CREATE PROCEDURE StartBlockedProcessNotification
    AS
    CREATE EVENT NOTIFICATION BlockedProcessNotification ON SERVER FOR BLOCKED_PROCESS_REPORT TO SERVICE 'BlockedProcessService', 'current database'
    GO
    
    EXEC sp_procoption 'StartBlockedProcessNotification', 'startup', 'on'
    EXEC StartBlockedProcessNotification
    
    USE msdb
    GO
    
    CREATE PROCEDURE BlockedProcessActivationProcedure
    AS
    
    --Service Broker
    DECLARE @message_body xml
    DECLARE @message_body_text nvarchar(max)
    DECLARE @dialog uniqueidentifier
    DECLARE @message_type nvarchar(256)
    
    WHILE 1 = 1
    BEGIN --Process the queue
        BEGIN TRANSACTION;
    
        RECEIVE TOP (1)
            @message_body = message_body,
            @dialog = conversation_handle,
            @message_type = message_type_name
        FROM BlockedProcessQueue
    
        IF @@ROWCOUNT = 0
        BEGIN
            RAISERROR('Nothing more to process', 0, 1)
            ROLLBACK TRANSACTION
            RETURN
        END
    
        IF @message_type = 'http://schemas.microsoft.com/SQL/Notifications/EventNotification'
        BEGIN
            DECLARE @mail_body nvarchar(max)
    
            DECLARE @post_time varchar(32)
            DECLARE @duration int
            DECLARE @blocked_spid int
            DECLARE @waitresource nvarchar(max)
            DECLARE @waitresource_db nvarchar(128)
            DECLARE @waitresource_schema nvarchar(128)
            DECLARE @waitresource_name nvarchar(128)
            DECLARE @blocked_hostname nvarchar(128)
            DECLARE @blocked_db nvarchar(128)
            DECLARE @blocked_login nvarchar(128)
            DECLARE @blocked_lasttranstarted nvarchar(32)
            DECLARE @blocked_inputbuf nvarchar(max)
            DECLARE @blocking_spid int
            DECLARE @blocking_hostname nvarchar(128)
            DECLARE @blocking_db nvarchar(128)
            DECLARE @blocking_login nvarchar(128)
            DECLARE @blocking_lasttranstarted nvarchar(32)
            DECLARE @blocking_inputbuf nvarchar(max)
    
            SET @post_time = CONVERT(varchar(32), @message_body.value(N'(//EVENT_INSTANCE/PostTime)[1]', 'datetime'), 109)
            SET @duration = CAST(@message_body.value(N'(//EVENT_INSTANCE/Duration)[1]', 'bigint') / 1000000 AS int)
            SET @blocked_spid = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/@spid)[1]', 'int')
            SET @waitresource = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/@waitresource)[1]', 'nvarchar(max)')
            SET @blocked_hostname = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/@hostname)[1]', 'nvarchar(128)')
            SET @blocked_db = DB_NAME(@message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/@currentdb)[1]', 'int'))
            SET @blocked_login = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/@loginname)[1]', 'nvarchar(128)')
            SET @blocked_lasttranstarted = CONVERT(varchar(32), @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/@lasttranstarted)[1]', 'datetime'), 109)
            SET @blocked_inputbuf = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process/inputbuf)[1]', 'nvarchar(max)')
            SET @blocking_spid = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process/@spid)[1]', 'int')
            SET @blocking_hostname = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process/@hostname)[1]', 'nvarchar(128)')
            SET @blocking_db = DB_NAME(@message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process/@currentdb)[1]', 'int'))
            SET @blocking_login = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process/@loginname)[1]', 'nvarchar(128)')
            SET @blocking_lasttranstarted = CONVERT(varchar(32), @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process/@lasttranstarted)[1]', 'datetime'), 109)
            SET @blocking_inputbuf = @message_body.value(N'(//EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process/inputbuf)[1]', 'nvarchar(max)')
    
            SELECT
                @waitresource_name = wait_resource_object_name,
                @waitresource_schema = wait_resource_schema_name,
                @waitresource_db = wait_resource_database_name
            FROM master.dbo.wait_resource_name(@waitresource)
    
            SET @mail_body = 'Posted: ' + ISNULL(@post_time, '') + CHAR(10) +
                'Duration: ' + ISNULL(CAST(@duration AS varchar) + ' s', '') + CHAR(10) +
                CHAR(10) +
                '==========Blocked Process==========' + CHAR(10) +
                'SPID: ' + ISNULL(CAST(@blocked_spid AS varchar), '') + CHAR(10) +
                'Wait Resource: ' + ISNULL(ISNULL(QUOTENAME(@waitresource_db) + '.' + QUOTENAME(@waitresource_schema) + '.' + QUOTENAME(@waitresource_name), @waitresource), '') + CHAR(10) +
                'Hostname: ' + ISNULL(@blocked_hostname, '') + CHAR(10) +
                'Current Database: ' + ISNULL(@blocked_db, '') + CHAR(10) +
                'Login Name: ' + ISNULL(@blocked_login, '') + CHAR(10) +
                'Last Transaction Started: ' + ISNULL(@blocked_lasttranstarted, '') + CHAR(10) +
                '----------Input Buffer----------' + CHAR(10) +
                ISNULL(@blocked_inputbuf, '') + CHAR(10) +
                CHAR(10) +
                '==========Blocking Process==========' + CHAR(10) +
                'SPID: ' + ISNULL(CAST(@blocking_spid AS varchar), '') + CHAR(10) +
                'Hostname: ' + ISNULL(@blocking_hostname, '') + CHAR(10) +
                'Current Database: ' + ISNULL(@blocking_db, '') + CHAR(10) +
                'Login Name: ' + ISNULL(@blocking_login, '') + CHAR(10) +
                'Last Transaction Started: ' + ISNULL(@blocking_lasttranstarted, '') + CHAR(10) +
                '----------Input Buffer----------' + CHAR(10) +
                ISNULL(@blocking_inputbuf, '') + CHAR(10)
    
            EXEC sp_send_dbmail @recipients = 'Your address here', @subject = 'Blocked Process Report', @body = @mail_body
        END
        ELSE IF @message_type IN ('http://schemas.microsoft.com/SQL/ServiceBroker/Error', 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
        BEGIN
            END CONVERSATION @dialog
        END
    
        COMMIT TRANSACTION
    END
    
    GO
    
    ALTER QUEUE BlockedProcessQueue WITH ACTIVATION (
        STATUS = ON,
        PROCEDURE_NAME = [BlockedProcessActivationProcedure],
        MAX_QUEUE_READERS = 1,
        EXECUTE AS OWNER
    )
    
    • 7
  2. Martin Smith
    2013-02-08T05:33:37+08:002013-02-08T05:33:37+08:00

    不确定是否有一些更简单的内置方法,但一种方法是首先将阻塞进程阈值配置为 60 秒。

    sp_configure 'show advanced options', 1 ;
    GO
    RECONFIGURE ;
    GO
    sp_configure 'blocked process threshold', 60 ;
    GO
    RECONFIGURE ;
    GO
    

    然后为BLOCKED_PROCESS_REPORT. 有关事件通知的示例代码,请参见此答案。

    您的激活程序可用于sp_send_dbmail发送电子邮件。

    • 4

相关问题

  • SQL Server 2008 R2 中的自动收缩、加密和恢复模型属性

  • SQL Server 2008 R2 群集的无人参与安装失败并出现错误 - “路径中有非法字符”。

  • 迁移大型数据库

  • 代理执行的维护计划

  • 随机化表内容并将它们存储回表中

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve