公司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