sqlserver監控阻塞(死鎖)具體狀況(轉)

  公司sqlserver的監控系統主要是採用zabbix監控,可是zabbix的監控只能經過性能計數器給出報警,而沒法給出具體的阻塞狀況,好比阻塞會話、語句、時間等,因此須要配合sqlserver的一些特性來進行監控,這裏給出一個方案:css

  1.建立阻塞日誌表,用於記錄阻塞狀況html

  2.新建做業,用於將阻塞狀況記錄到阻塞日誌表中,併發送郵件(若是沒有配置郵件,或者不須要發送郵件,能夠忽略此步驟)sql

  3.建立警報,當阻塞大於閾值時,觸發上面做業數據庫

  在數據庫阻塞值大於閾值時,在原有zabbix的監控上,將阻塞報警以短信和郵件方式發送給dba,同時將阻塞信息記錄到阻塞記錄表中,將阻塞的具體信息經過郵件形式發送給aba,幫助dba進行系統診斷。session

  查詢阻塞狀況依賴於如下sql:併發

複製代碼
--查詢阻塞
SELECT  R.session_id AS BlockedSessionID ,  
        S.session_id AS BlockingSessionID ,  
        Q1.text AS BlockedSession_TSQL ,  
        Q2.text AS BlockingSession_TSQL ,  
        C1.most_recent_sql_handle AS BlockedSession_SQLHandle ,  
        C2.most_recent_sql_handle AS BlockingSession_SQLHandle ,  
        S.original_login_name AS BlockingSession_LoginName ,  
        S.program_name AS BlockingSession_ApplicationName ,  
        S.host_name AS BlockingSession_HostName  
FROM    sys.dm_exec_requests AS R  
        INNER JOIN sys.dm_exec_sessions AS S ON R.blocking_session_id = S.session_id  
        INNER JOIN sys.dm_exec_connections AS C1 ON R.session_id = C1.most_recent_session_id  
        INNER JOIN sys.dm_exec_connections AS C2 ON S.session_id = C2.most_recent_session_id  
        CROSS APPLY sys.dm_exec_sql_text(C1.most_recent_sql_handle) AS Q1  
        CROSS APPLY sys.dm_exec_sql_text(C2.most_recent_sql_handle) AS Q2
複製代碼

對sql進行測試,表t中只有一條數據。會話1中執行如下sqltcp

會話2執行sql後產生阻塞sqlserver

用該sql查詢的結果:性能

  對於該sql的字段很簡單,blocked開頭的表示被阻塞的,blocking表示阻塞的。測試

一.建立阻塞日誌表,用於記錄阻塞狀況

複製代碼
USE etcp_alert 
GO 
CREATE TABLE [dbo].[BlockLog]
    (
      Id INT IDENTITY(1, 1)
             NOT NULL
             PRIMARY KEY ,
      [BlockingSessesionId] [smallint] NULL ,
      [ProgramName] [nchar](128) NULL ,
      [HostName] [nchar](128) NULL ,
      [ClientIpAddress] [varchar](48) NULL ,
      [DatabaseName] [sysname] NOT NULL ,
      [WaitType] [nvarchar](60) NULL ,
      [BlockingStartTime] [datetime] NOT NULL ,
      [WaitDuration] [bigint] NULL ,
      [BlockedSessionId] [int] NULL ,
      [BlockedSQLText] [nvarchar](MAX) NULL ,
      [BlockingSQLText] [nvarchar](MAX) NULL ,
      [dt] [datetime] NOT NULL
    )
ON  [PRIMARY]
GO
複製代碼

2、新建做業,用於將阻塞狀況記錄到阻塞日誌表中,併發送郵件

  

  

在新建做業步驟中,選擇數據庫tempdb,並插入代碼:

複製代碼
SET NOCOUNT ON;
DECLARE @dt DATETIME= GETDATE();
 -- 阻塞時間
DECLARE @HtmlContent NVARCHAR(MAX);
 --郵件發送的阻塞日誌(表格形式)

IF OBJECT_ID('tempdb.dbo.#BlockLog') IS NOT NULL 
    DROP TABLE #BlockLog;     
--將當前日誌記錄插入臨時表
BEGIN  
    SELECT  wt.blocking_session_id AS BlockingSessesionId ,
            sp.program_name AS ProgramName ,
            COALESCE(sp.LOGINAME, sp.nt_username) AS HostName ,
            ec1.client_net_address AS ClientIpAddress ,
            db.name AS DatabaseName ,
            wt.wait_type AS WaitType ,
            ec1.connect_time AS BlockingStartTime ,
            wt.WAIT_DURATION_MS / 1000 AS WaitDuration ,
            ec1.session_id AS BlockedSessionId ,
            h1.TEXT AS BlockedSQLText ,
            h2.TEXT AS BlockingSQLText ,
            @dt dt
    INTO    #BlockLog
    FROM    sys.dm_tran_locks AS tl
            INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id
            INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
            INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
            INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
            LEFT OUTER JOIN master.dbo.sysprocesses sp ON SP.spid = wt.blocking_session_id
            CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
            CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2;         
--將臨時表數據插入日誌表
    INSERT  INTO etcp_alert.dbo.BlockLog
            ( BlockingSessesionId ,
              ProgramName ,
              HostName ,
              ClientIpAddress ,
              DatabaseName ,
              WaitType ,
              BlockingStartTime ,
              WaitDuration ,
              BlockedSessionId ,
              BlockedSQLText ,
              BlockingSQLText ,
              dt
            )
            SELECT  BlockingSessesionId ,
                    ProgramName ,
                    HostName ,
                    ClientIpAddress ,
                    DatabaseName ,
                    WaitType ,
                    BlockingStartTime ,
                    WaitDuration ,
                    BlockedSessionId ,
                    BlockedSQLText ,
                    BlockingSQLText ,
                    dt
            FROM    #BlockLog;
END;
--以html表格方式發送郵件,若是不發送郵件,則刪除如下代碼
BEGIN
    SET @HtmlContent = N'<head>'
        + N'<style type="text/css">h2, body {font-family: Arial, verdana;} table{font-size:11px; border-collapse:collapse;} td{ border:1px solid black; padding:3px;} th{background-color:#99CCFF;}</style>'
        + N'<table border="1">' + N'<tr>
                 <th>BlockingSessesionId</th>
                 <th>ProgramName</th>
                 <th>HostName</th>
                 <th>ClientIpAddress</th>
                 <th>DatabaseName</th>
                 <th>WaitType</th>
                 <th>BlockingStartTime</th>
                 <th>WaitDuration</th>
                 <th>BlockedSessionId</th> 
                 <th>BlockedSQLText</th>
                 <th>BlockingSQLText</th>
                 <th>dt</th>
                </tr>' + CAST(( SELECT  BlockingSessesionId AS TD ,
                                        '' ,
                                        ProgramName AS TD ,
                                        '' ,
                                        HostName AS TD ,
                                        '' ,
                                        ClientIpAddress AS TD ,
                                        '' ,
                                        DatabaseName AS TD ,
                                        '' ,
                                        WaitType AS TD ,
                                        '' ,
                                        BlockingStartTime AS TD ,
                                        '' ,
                                        WaitDuration AS TD ,
                                        '' ,
                                        BlockedSessionId AS TD ,
                                        '' ,
                                        BlockedSQLText AS TD ,
                                        '' ,
                                        BlockingSQLText AS TD ,
                                        '' ,
                                        dt AS Td ,
                                        ''
                                FROM    #BlockLog
                              FOR
                                XML PATH('tr') ,
                                    TYPE
                              ) AS NVARCHAR(MAX)) + N'</table>';
    IF @HtmlContent IS NOT NULL 
        BEGIN
            DECLARE @ProfileName VARCHAR(100)= 'db_mail'; --郵箱公用帳戶名稱
            DECLARE @RecipientsLst VARCHAR(100)= '123@123.cn';  --收件人,以";"分隔
            DECLARE @subject VARCHAR(100)= '數據庫阻塞警報'; --主題
            EXEC msdb.dbo.sp_send_dbmail @profile_name = @ProfileName,
                @recipients = @RecipientsLst, @subject = @subject,
                @body = @HtmlContent, @body_format = 'HTML'; 
        END;  
    begin  
        DROP TABLE #BlockLog;  
    END;                              
END;
複製代碼

注意,若是沒有配置郵箱帳號,須要配置郵箱功能,以下:

3、建立警報,當阻塞大於閾值時,觸發上面做業

名稱:可根據實際自行命名,這裏我用數據庫阻塞報警
類型:選擇"SQL Server性能條件警報"
對象:SQLServer:General Statistics
計數器:Processes blocked
計數器知足如下條件時觸發警報:高於
值:2,根據系統具體定

在"響應"中配置,必定將執行做業指向上面建立的job

4、測試

爲了測試方便,我將報警閾值調整爲高於0個,即當1個阻塞發生時就會觸發對應的job,仍是採用以前的兩個會話,查看報警。

郵箱收到報警:

結果表已經插入數據:

 

轉:

https://www.cnblogs.com/datazhang/p/4773823.html

相關文章
相關標籤/搜索