SQL Server 收集数据库死锁信息

背景

我们在数据库出现阻塞及时邮件预警提醒中监控了数据库的阻塞情况,为了更好的维护数据库,特别是提升终端客户用户体验,我们要尽量避免在数据库中出现死锁的情况。我们知道收集死锁可以开启跟踪标志如1204,然后在日志中查看死锁相关信息,或者使用Profiler去跟踪死锁,我们希望所有的死锁信息收集到某表供我们后期优化分析使用,我们可以使用相对比较轻量的自带扩展事件(system_health)来完成这个需求。

测试环境

Microsoft SQL Server 2012 - 11.0.2100.60 (X64)

Feb 10 2012 19:39:15

Copyright (c) Microsoft Corporation

Enterprise Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: )

实现过程

a.新建存放死锁的表

IF DB_ID(‘azure_monitor‘) IS NULL
BEGIN
CREATE DATABASE azure_monitor ;
END
GO 

ALTER DATABASE azure_monitor SET RECOVERY SIMPLE;
GO 

USE [azure_monitor];    --存放死锁信息的库名
GO

IF OBJECT_ID(‘monitor_deadlock‘, ‘U‘) IS NOT NULL
    DROP TABLE dbo.monitor_deadlock;
GO
CREATE TABLE [dbo].[monitor_deadlock]
    (
      [ServerName] [VARCHAR](50),
      [DataBaseName] [NVARCHAR](100) NULL ,
      [DeadlockID] [BIGINT] NULL ,
      [TransactionTime] [DATETIME] NULL ,
      [DeadlockGraph] [XML] NULL ,
      [DeadlockObjects] [NVARCHAR](MAX) NULL ,
      [Victim] [INT] NOT NULL ,
      [SPID] [INT] NULL ,
      [ProcedureName] [VARCHAR](200) NULL ,
      [LockMode] [CHAR](1) NULL ,
      [Code] [VARCHAR](1000) NULL ,
      [ClientApp] [NVARCHAR](245) NULL ,
      [HostName] [VARCHAR](20) NULL ,
      [LoginName] [VARCHAR](20) NULL ,
      [InputBuffer] [VARCHAR](1000) NULL ,
      [Capture_date] [DATETIME] NOT NULL ,
      [capture_day] AS ( CONVERT([VARCHAR](12), [Capture_date], ( 112 )) ) ,
      [comfirm_user] [NVARCHAR](50) NULL ,
      [comfirm_flag] [INT] NOT NULL
    )
ON  [PRIMARY] TEXTIMAGE_ON [PRIMARY];
GO
ALTER TABLE [dbo].[monitor_deadlock] ADD  CONSTRAINT [DF__monitor_d__Captu__2CF2ADDF]  DEFAULT (GETDATE()) FOR [Capture_date];
GO
ALTER TABLE [dbo].[monitor_deadlock] ADD  CONSTRAINT [DF__monitor_d__comfi__2DE6D218]  DEFAULT ((1)) FOR [comfirm_flag];
GO

b.新建读取死锁的存储过程

USE [azure_monitor];
    --存放读取死锁信息的存储过程的库名
GO
IF OBJECT_ID(‘monitor_P_deadlock‘, ‘P‘) IS  NULL
    EXEC( ‘CREATE  procedure dbo.monitor_P_deadlock AS  ‘);
GO
/*=============================================
-- Author:    jil.wen
-- Create date: 2017/04/11
-- Description:   监控数据库上死锁情况;
-- demo :   exec dbo.monitor_P_deadlock
 ============================================= */
ALTER PROCEDURE monitor_P_deadlock
AS
    BEGIN
      -- DELETE  FROM dbo.monitor_deadlock
      --  WHERE   [capture_day] = CONVERT([VARCHAR](12), GETDATE(), ( 112 ))
      --          AND comfirm_flag = 1;
        DECLARE @SessionName sysname;
        DECLARE @Servername VARCHAR(50);
        SELECT  @Servername = @@SERVERNAME;
        SELECT  @SessionName = ‘system_health‘;
/*
SELECT  Session_Name = s.name, s.blocked_event_fire_time, s.dropped_buffer_count, s.dropped_event_count, s.pending_buffers
FROM sys.dm_xe_session_targets t
            INNER JOIN sys.dm_xe_sessions s ON s.address = t.event_session_address
WHERE target_name = ‘event_file‘
--*/
        IF OBJECT_ID(‘tempdb..#Events‘) IS NOT NULL
            BEGIN
                DROP TABLE #Events;
            END;
        DECLARE @Target_File NVARCHAR(1000) ,
            @Target_Dir NVARCHAR(1000) ,
            @Target_File_WildCard NVARCHAR(1000);
        SELECT  @Target_File = CAST(t.target_data AS XML).value(‘EventFileTarget[1]/File[1]/@name‘,
                                                              ‘NVARCHAR(256)‘)
        FROM    sys.dm_xe_session_targets t
                INNER JOIN sys.dm_xe_sessions s ON s.address = t.event_session_address
        WHERE   s.name = @SessionName
                AND t.target_name = ‘event_file‘;
        SELECT  @Target_Dir = LEFT(@Target_File,
                                   LEN(@Target_File) - CHARINDEX(‘\‘,
                                                              REVERSE(@Target_File)));
        SELECT  @Target_File_WildCard = @Target_Dir + ‘\‘ + @SessionName
                + ‘_*.xel‘;
--Keep this as a separate table because it‘s called twice in the next query.  You don‘t want this running twice.
        SELECT  DeadlockGraph = CAST(event_data AS XML) ,
                DeadlockID = ROW_NUMBER() OVER ( ORDER BY file_name, file_offset )
        INTO    #Events
        FROM    sys.fn_xe_file_target_read_file(@Target_File_WildCard, NULL,
                                                NULL, NULL) AS F
        WHERE   event_data LIKE ‘<event name="xml_deadlock_report%‘;
        WITH    Victims
                  AS ( SELECT   VictimID = Deadlock.Victims.value(‘@id‘,
                                                              ‘varchar(50)‘) ,
                                e.DeadlockID
                       FROM     #Events e
                                CROSS APPLY e.DeadlockGraph.nodes(‘/event/data/value/deadlock/victim-list/victimProcess‘)
                                AS Deadlock ( Victims )
                     ),
                DeadlockObjects
                  AS ( SELECT DISTINCT
                                e.DeadlockID ,
                                ObjectName = Deadlock.Resources.value(‘@objectname‘,
                                                              ‘nvarchar(256)‘)
                       FROM     #Events e
                                CROSS APPLY e.DeadlockGraph.nodes(‘/event/data/value/deadlock/resource-list/*‘)
                                AS Deadlock ( Resources )
                     )
            INSERT  INTO monitor_deadlock
                    ( ServerName ,
                      DataBaseName ,
                      DeadlockID ,
                      TransactionTime ,
                      DeadlockGraph ,
                      DeadlockObjects ,
                      Victim ,
                      SPID ,
                      ProcedureName ,
                      LockMode ,
                      Code ,
                      ClientApp ,
                      HostName ,
                      LoginName ,
                      InputBuffer
                    )
                    SELECT  @Servername AS ServerName ,
                            DatabaseName ,
                            DeadlockID ,
                            TransactionTime ,
                            DeadlockGraph ,
                            DeadlockObjects ,
                            Victim ,
                            SPID ,
                            ProcedureName ,
                            LockMode ,
                            Code ,
                            ClientApp ,
                            HostName ,
                            LoginName ,
                            InputBuffer
                    FROM    ( SELECT    DatabaseName = LEFT(SUBSTRING(( SELECT
                                                              ( ‘, ‘
                                                              + o.ObjectName )
                                                              FROM
                                                              DeadlockObjects o
                                                              WHERE
                                                              o.DeadlockID = e.DeadlockID
                                                              ORDER BY o.ObjectName
                                                              FOR
                                                              XML
                                                              PATH(‘‘)
                                                              ), 3, 4000),
                                                            CHARINDEX(‘.‘,
                                                              SUBSTRING(( SELECT
                                                              ( ‘, ‘
                                                              + o.ObjectName )
                                                              FROM
                                                              DeadlockObjects o
                                                              WHERE
                                                              o.DeadlockID = e.DeadlockID
                                                              ORDER BY o.ObjectName
                                                              FOR
                                                              XML
                                                              PATH(‘‘)
                                                              ), 3, 4000)) - 1) ,
                                        e.DeadlockID ,
                                        TransactionTime = Deadlock.Process.value(‘@lasttranstarted‘,
                                                              ‘datetime‘) ,
                                        DeadlockGraph ,
                                        DeadlockObjects = SUBSTRING(( SELECT
                                                              ( ‘, ‘
                                                              + o.ObjectName )
                                                              FROM
                                                              DeadlockObjects o
                                                              WHERE
                                                              o.DeadlockID = e.DeadlockID
                                                              ORDER BY o.ObjectName
                                                              FOR
                                                              XML
                                                              PATH(‘‘)
                                                              ), 3, 4000) ,
                                        Victim = CASE WHEN v.VictimID IS NOT NULL
                                                      THEN 1
                                                      ELSE 0
                                                 END ,
                                        SPID = Deadlock.Process.value(‘@spid‘,
                                                              ‘int‘) ,
                                        ProcedureName = Deadlock.Process.value(‘executionStack[1]/frame[1]/@procname[1]‘,
                                                              ‘varchar(200)‘) ,
                                        LockMode = Deadlock.Process.value(‘@lockMode‘,
                                                              ‘char(1)‘) ,
                                        Code = Deadlock.Process.value(‘executionStack[1]/frame[1]‘,
                                                              ‘varchar(1000)‘) ,
                                        ClientApp = CASE LEFT(Deadlock.Process.value(‘@clientapp‘,
                                                              ‘varchar(100)‘),
                                                              29)
                                                      WHEN ‘SQLAgent - TSQL JobStep (Job ‘
                                                      THEN ‘SQLAgent Job: ‘
                                                           + ( SELECT
                                                              name
                                                              FROM
                                                              msdb..sysjobs sj
                                                              WHERE
                                                              SUBSTRING(Deadlock.Process.value(‘@clientapp‘,
                                                              ‘varchar(100)‘),
                                                              32, 32) = ( SUBSTRING(sys.fn_varbintohexstr(sj.job_id),
                                                              3, 100) )
                                                             ) + ‘ - ‘
                                                           + SUBSTRING(Deadlock.Process.value(‘@clientapp‘,
                                                              ‘varchar(100)‘),
                                                              67,
                                                              LEN(Deadlock.Process.value(‘@clientapp‘,
                                                              ‘varchar(100)‘))
                                                              - 67)
                                                      ELSE Deadlock.Process.value(‘@clientapp‘,
                                                              ‘varchar(100)‘)
                                                    END ,
                                        HostName = Deadlock.Process.value(‘@hostname‘,
                                                              ‘varchar(20)‘) ,
                                        LoginName = Deadlock.Process.value(‘@loginname‘,
                                                              ‘varchar(20)‘) ,
                                        InputBuffer = Deadlock.Process.value(‘inputbuf[1]‘,
                                                              ‘varchar(1000)‘)
                              FROM      #Events e
                                        CROSS APPLY e.DeadlockGraph.nodes(‘/event/data/value/deadlock/process-list/process‘)
                                        AS Deadlock ( Process )
                                        LEFT JOIN Victims v ON v.DeadlockID = e.DeadlockID
                                                              AND v.VictimID = Deadlock.Process.value(‘@id‘,
                                                              ‘varchar(50)‘)
                            ) X --In a subquery to make filtering easier (use column names, not XML parsing), no other reason
ORDER BY                    DeadlockID DESC;
    END;

c.在Agent新建job调用上述【monitor_P_deadlock】存储过程

省略,详情可以参考数据库出现阻塞及时邮件预警提醒(下)

d.收集效果如下

注意事项

  • 如需使用Agent代理发送预警邮件,就要注意Agent是否正常运行;
  • 是否有调用上述脚本的数据库用户权限;
  • 数据库自带扩展事件system_health是否正常运行;

  

时间: 2024-12-29 11:56:08

SQL Server 收集数据库死锁信息的相关文章

微软ASP.NET站点部署指南(2):部署SQL Server Compact数据库

1. 综述 对于数据库访问,Contoso University程序要求下面的软件必须随程序一起部署,因为不属于.NET Framework: SQL Server Compact (数据库引擎) ASP.NET Universal Providers (启用ASP.NET membership以使用SQL Server Compact) Entity Framework 4.1 (Code First) 2个数据库的数据库结构和相关的一些数据都需要部署.通常,开发系统的时候都会有一些测试数据,

微软ASP.NET网站部署指南(2):部署SQL Server Compact数据库

1. 综述 对于数据库訪问,Contoso University程序要求以下的软件必须随程序一起部署.由于不属于.NET Framework: SQL Server Compact (数据库引擎) ASP.NET Universal Providers (启用ASP.NET membership以使用SQL Server Compact) Entity Framework 4.1 (Code First) 2个数据库的数据库结构和相关的一些数据都须要部署.通常.开发系统的时候都会有一些測试数据,

SQL SERVER性能分析--死锁检测数据库阻塞语句

工作中数据库经常出现内存,找了篇文章 参照CSDN,中国风(Roy)一篇死锁文章 阻塞:其中一个事务阻塞,其它事务等待对方释放它们的锁,同时会导致死锁问题. 整理人:中国风(Roy) 参照Roy_88的博客 http://blog.csdn.net/roy_88/archive/2008/07/21/2682044.aspx 日期:2008.07.20 ************************************************************************

SQL Server Profiler -- 调试死锁

SQL Server Profiler -- 调试死锁 跟踪一般的异常很简单,但处理死锁很难,死锁的消息号为1205,严重度为13.从服务器无法得到足够的数据来帮助判断到底发生了什么及为什么会发生这种状况,甚至服务器返回的错误消息也没有价值,这种消息所提供的唯一建议就是可以"重新运行该事务". SQL跟踪有提供帮助隔离和调试死锁状态的工具,但是SQL Server 2005把这些工具提升到了一个新的层次,它提供了一个非常有用的图形界面,帮助用户解决这些难以应付的问题.为了阐明到底提供了

深入浅出SQL Server中的死锁 【转】

简介 死锁的本质是一种僵持状态,是多个主体对于资源的争用而导致的.理解死锁首先需要对死锁所涉及的相关观念有一个理解. 一些基础知识 要理解SQL Server中的死锁,更好的方式是通过类比从更大的面理解死锁.比如说一个经典的例子就是汽车(主体)对于道路(资源)的征用,如图1所示. 图1.对于死锁的直观理解 在图1的例子中,每队汽车都占有一条道路,但都需要另外一队汽车所占有的另一条道路,因此互相阻塞,谁都无法前行,因此造成了死锁.由这个简单的例子可以看出,发生死锁需要四个必要条件,如下: 1)互斥

SQL Server中解决死锁的新方法介绍

SQL Server中解决死锁的新方法介绍 数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL Server 2005, 现在似乎有了一种新的解决办法. 将下面的SQL语句放在两个不同的连接里面,并且在5秒内同时执行,将会发生死锁. <ccid_nobr> <ccid_code>use Northwindbegin tran insert into Orders(CustomerId) values(@#[email protected]#)

SQL Server中解决死锁

SQL Server中解决死锁的新方法介绍 数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL Server 2005, 现在似乎有了一种新的解决办法. 将下面的SQL语句放在两个不同的连接里面,并且在5秒内同时执行,将会发生死锁. <ccid_nobr> <ccid_code>use Northwindbegin tran insert into Orders(CustomerId) values(@#[email protected]#)

深入浅出SQL Server中的死锁

简介 死锁的本质是一种僵持状态,是多个主体对于资源的争用而导致的.理解死锁首先需要对死锁所涉及的相关观念有一个理解. 一些基础知识 要理解SQL Server中的死锁,更好的方式是通过类比从更大的面理解死锁.比如说一个经典的例子就是汽车(主体)对于道路(资源)的征用,如图1所示. 图1.对于死锁的直观理解 在图1的例子中,每队汽车都占有一条道路,但都需要另外一队汽车所占有的另一条道路,因此互相阻塞,谁都无法前行,因此造成了死锁.由这个简单的例子可以看出,发生死锁需要四个必要条件,如下: 1)互斥

深入浅出 关于SQL Server中的死锁问题

深入浅出 关于SQL Server中的死锁问题 博客2013-02-12 13:44 分享到:我要吐槽 死锁的本质是一种僵持状态,是多个主体对于资源的争用而导致的.理解死锁首先需要对死锁所涉及的相关观念有一个理解. 一些基础知识 要理解SQL Server中的死锁,更好的方式是通过类比从更大的面理解死锁.比如说一个经典的例子就是汽车(主体)对于道路(资源)的征用,如图1所示. 图1.对于死锁的直观理解 在图1的例子中,每队汽车都占有一条道路,但都需要另外一队汽车所占有的另一条道路,因此互相阻塞,