数据库出现阻塞及时邮件预警提醒(下)
在数据库出现阻塞及时邮件预警提醒(上)中我们新建存放阻塞记录的表和收集阻塞的存储过程并配置发送邮件测试ok等事项。
第四步:创建发送邮件的存储过程,有两种模式,可以根据需要选择
创建发送阻塞邮件的存储过程
---第一种是有附件模式(监控阻塞)
USE azure_monitor; GO IF OBJECT_ID('monitor_p_sent_mail', 'P') IS NOT NULL DROP PROCEDURE monitor_p_sent_mail; GO ----监控库 sql server blocking 的存储过程例子 /*============================================= -- Author: jil.wen -- Create date: 2016/11/16 -- Description: 新建存储过程发送关于阻塞的邮件; -- demo : exec dbo.monitor_p_sent_mail ============================================= */ CREATE PROCEDURE monitor_p_sent_mail AS BEGIN --注意替换库名的修改 SET NOCOUNT ON; IF EXISTS ( SELECT 1 FROM azure_monitor..Monitor_blocking WHERE blocking_date = ( CONVERT([VARCHAR](100), GETDATE(), ( 23 )) ) AND confirm_flag = 0 AND [database] = N'替换成实际被监控的库名' ) --替换成实际的库名 BEGIN DECLARE @getdate VARCHAR(200); DECLARE @xiangmu VARCHAR(200); SELECT @xiangmu='某某项目名称' --替换成实际的项目名称 SELECT @getdate =@xiangmu + '【' + CONVERT(VARCHAR(12), GETDATE(), 112) + ' 出现阻塞预警】'; EXEC msdb.dbo.sp_send_dbmail @profile_name = 'monitor_blocking', @recipients = '某某@qq.com;', ---收件人,多个邮箱用【;】区分 @copy_recipients = 'someone@163.com;', --抄送人 @query = 'SELECT [lock type], [database], [blk object], [lock req], [waiter sid], [wait time], waiter_batch, waiter_stmt, [blocker sid], blocker_stmt, time, blocking_date FROM azure_monitor..monitor_blocking WHERE blocking_date=(CONVERT([varchar](100),GETDATE(),(23))) and confirm_flag = 0 and [database]=N''替换成实际被监控的库名''', @subject = @getdate, @body = '各位好, 数据库已出现阻塞了,如需查看阻塞语句请使用下述脚本: SELECT [lock type] , [database] , [blk object] , [lock req] , [waiter sid] , [wait time] , waiter_batch , waiter_stmt , [blocker sid] , blocker_stmt , time , blocking_date FROM azure_monitor..monitor_blocking WHERE blocking_date = ( CONVERT([varchar](100), GETDATE(), ( 23 )) ) and confirm_flag = 0 and [database]=N''替换成实际被监控的库名'' --请替换成实际的库名 请及时响应并更改已处理阻塞的处理状态,不然会一直发送预警邮件,建议处理阻塞状态脚本如下语句: 例如: UPDATE azure_monitor..Monitor_blocking SET confirm_flag = 1 , --处理标志 confirm_user = N''张三'' , --更新人 confirm_date = GETDATE() --处理时间 WHERE blocking_date = ( CONVERT([VARCHAR](100), GETDATE(), ( 23 )) ) --阻塞日期 AND [database] = N''替换成实际被监控的库名'' --替换成实际的库名 AND [time] < DATEADD(MINUTE, -15, GETDATE()); ---当前时间向前推15分钟 ', @attach_query_result_as_file = 1; END; SET NOCOUNT OFF; END;
---第二种是HTML格式(监控阻塞)
USE azure_monitor; GO IF OBJECT_ID('monitor_p_sent_mail', 'P') IS NOT NULL DROP PROCEDURE monitor_p_sent_mail; GO ----监控库 sql server blocking 的存储过程例子 /*============================================= -- Author: jil.wen -- Create date: 2016/11/16 -- Description: 新建存储过程发送关于阻塞的邮件; -- demo : exec dbo.monitor_p_sent_mail ============================================= */ CREATE PROCEDURE [dbo].[monitor_p_sent_mail] AS BEGIN --注意替换库名的修改 SET NOCOUNT ON; IF EXISTS ( SELECT 1 FROM azure_monitor..Monitor_blocking WHERE blocking_date = ( CONVERT([VARCHAR](100), GETDATE(), ( 23 )) ) AND confirm_flag = 0 AND [database] = N'替换成实际库名' ) --替换成被监控的实际库名 BEGIN DECLARE @xml NVARCHAR(MAX); DECLARE @body NVARCHAR(MAX); SET @xml = CAST(( SELECT [lock type] AS 'td' , '' , [database] AS 'td' , '' , [blk object] AS 'td' , '' , [lock req] AS 'td' , '' , [waiter sid] AS 'td' , '' , [wait time] AS 'td' , '' , waiter_batch AS 'td' , '' , waiter_stmt AS 'td' , '' , [blocker sid] AS 'td' , '' , blocker_stmt AS 'td' , '' , [time] AS 'td' , '' , blocking_date AS 'td' FROM azure_monitor..Monitor_blocking WHERE confirm_flag = 0 AND [database] = N'替换成实际库名' AND blocking_date = CONVERT([VARCHAR](100), GETDATE(), ( 23 )) FOR XML PATH('tr') , ELEMENTS ) AS NVARCHAR(MAX)); SET @body = '<html><body><H3>某某项目_Write_DB Blocking Info</H3> <table border = 1> <tr> <th> lock type </th> <th> database </th> <th> blk object </th> <th> lock req </th><th> waiter sid </th><th> wait time </th><th> waiter_batch </th><th> waiter_stmt </th><th> blocker sid </th><th> blocker_stmt </th><th> time </th><th> blocking_date</th></tr>'; SET @body = N'各位好,' + CHAR(13) + CHAR(10) + N' 数据库已出现阻塞了,如需查看阻塞语句请使用下述脚本:' + CHAR(13) + CHAR(10) + N'SELECT [lock type] ,' + CHAR(13) + CHAR(10) + N'[database] ,' + CHAR(13) + CHAR(10) + N'[blk object] ,' + CHAR(13) + CHAR(10) + N'[lock req] ,' + CHAR(13) + CHAR(10) + N'[waiter sid] ,' + CHAR(13) + CHAR(10) + N'[wait time] ,' + CHAR(13) + CHAR(10) + N'waiter_batch ,' + CHAR(13) + CHAR(10) + N'waiter_stmt ,' + CHAR(13) + CHAR(10) + N'[blocker sid] ,' + CHAR(13) + CHAR(10) + N'blocker_stmt ,' + CHAR(13) + CHAR(10) + N'time ,' + CHAR(13) + CHAR(10) + N'blocking_date' + CHAR(13) + CHAR(10) + N' FROM azure_monitor..monitor_blocking' + CHAR(13) + CHAR(10) + N' WHERE blocking_date = ( CONVERT([varchar](100), GETDATE(), ( 23 )) ) and confirm_flag = 0 and [database]=N''替换实际库名''' + CHAR(13) + CHAR(10) + N' 请及时响应并更改已处理阻塞的处理状态,不然会一直发送预警邮件,建议处理阻塞状态脚本如下语句:' + CHAR(13) + CHAR(10) + N' 例如:' + CHAR(13) + CHAR(10) + N' UPDATE azure_monitor..Monitor_blocking' + CHAR(13) + CHAR(10) + N' SET confirm_flag = 1 , ' + CHAR(13) + CHAR(10) + N' confirm_user = N''张三'' , ' + CHAR(13) + CHAR(10) + N' confirm_date = GETDATE() ' + CHAR(13) + CHAR(10) + N' WHERE blocking_date = ( CONVERT([VARCHAR](100), GETDATE(), ( 23 )) ) ' + CHAR(13) + CHAR(10) + N' AND [database] = N''替换成实际库名'' ' + CHAR(13) + CHAR(10) + +@body + @xml + '</table></body></html>'; DECLARE @getdate VARCHAR(200); SELECT @getdate = '【' + CONVERT(VARCHAR(12), GETDATE(), 112) + ' 出现阻塞预警】'; EXEC msdb.dbo.sp_send_dbmail @profile_name = 'monitor_blocking', @recipients = '某A@163.com;某B@263.com;某C@QQ.com ;', ---收件人 @copy_recipients = '某D@139.com;', --抄送人 @body = @body, @body_format = 'HTML', @subject = @getdate; END; SET NOCOUNT OFF; END;
第五步:在Agent创建job通过计划定时执行第二步和第四步的存储过程
总结
1.邮件配置设置很重要,密码、端口是否正确,是否有防火墙等,提前验证邮件是否能正常发送成功;可以参考如下脚本辅助排查。
--SENT MESSAGES LOG SELECT TOP 20 * FROM [msdb].[dbo].[sysmail_sentitems] ORDER BY [send_request_date] DESC --FAILED MESSAGES LOG SELECT TOP 20 * FROM [msdb].[dbo].[sysmail_faileditems] ORDER BY [send_request_date] DESC --ALL MESSAGES – REGARDLESS OF STATUS SELECT TOP 20 * FROM [msdb].[dbo].[sysmail_allitems] ORDER BY [send_request_date] DESC
2.邮件能否重复发送基于Agent代理是否正常运转;
3.如有实例中有多个库,细分对应的人员不同,可以根据数据库名称不同,在job中定义多个step来处理;
4.注意调用上述脚本的数据库用户权限问题;
5.注意及时响应,并处理阻塞表中confirm_flag标志问题,避免多次重复发送邮件或已处理阻塞的信息;
6.如果当前捕获的阻塞或长查询量非常大,可能会造成发送邮件失败,注意关注job历史记录情况;