经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MS SQL Server » 查看文章
SQL Server邮件相关SQL语句出现严重的ASYNC_NETWORK_IO等待事件案例
来源:cnblogs  作者:潇湘隐者  时间:2020/11/9 15:56:11  对本文有异议

 

DPA监控发现一台SQL Server服务器最近两天执行系统存储过程msdb.dbo.sp_MailItemResultSets中的某个SQL时,出现较严重的ASYNC_NETWORK_IO等待。如下截图所示

 

clip_image001

 

进一步分析发现,主要是执行存储过程msdb.dbo.sp_MailItemResultSets中下面这段SQL语句出现ASYNC_NETWORK_IO等待

 

  1. SELECT 
  1.       mi.mailitem_id,
  1.       mi.profile_id,
  1.       (SELECT name FROM msdb.dbo.sysmail_profile p WHERE p.profile_id = mi.profile_id) as 'profile_name',
  1.       mi.recipients,
  1.       mi.copy_recipients,
  1.       mi.blind_copy_recipients,
  1.       mi.subject,
  1.       mi.body,
  1.       mi.body_format,
  1.       mi.importance,
  1.       mi.sensitivity,
  1.       ISNULL(sr.send_attempts, 0) as retry_attempt,
  1.       ISNULL(mi.from_address, '') as from_address,
  1.       ISNULL(mi.reply_to, '')     as reply_to
  1.    FROM sysmail_mailitems as mi
  1.       LEFT JOIN sysmail_send_retries as sr
  1.          ON sr.mailitem_id = mi.mailitem_id
  1.    WHERE mi.mailitem_id = @mailitem_id

 

进一步分析,发现随便一个与表sysmail_allitems有关的SQL都会出现严重的ASYNC_NETWORK_IO等待:

 

  1. SELECT * FROM msdb.dbo.sysmail_allitems WITH(NOLOCK)
  1. WHERE sent_status != 'sent' 
  1. ORDER BY sent_date DESC;

 

另外,分析过程中发现sysmail_mailitems表只有7万多条记录,但是表的Size大小接近10G大小,如下截图所示:

 

 

clip_image002

 

 

这显然明显不正常,sysmail_mailitems中肯定有一些超大的邮件记录,因为这个系统经常有通过SQL,生成一些报表数据发送给用户。于是我想检查一下是否真的有一些超大的邮件。这里就必须查看sysmail_mailitems表的行大小,于是用下面脚本查看表sysmail_mailitems中行记录的大小。

 

  1. USE msdb;
  1. GO
  1.  
  1. IF object_id('sp_GetRowSize') is not null
  1. drop procedure sp_GetRowSize
  1. GO
  1. CREATE procedure sp_GetRowSize(@Tablename varchar(100),@pkcol varchar(100))
  1. AS 
  1. BEGIN
  1. declare @dynamicsql varchar(MAX)
  1.  
  1. -- A @pkcol can be used to identify max/min length row
  1. set @dynamicsql = 'select ' + @PkCol +' , (0'
  1.  
  1. -- traverse each record and calculate the datalength
  1. select @dynamicsql = @dynamicsql + ' + isnull(datalength(' + name + '), 1)' 
  1.     from syscolumns where id = object_id(@Tablename)
  1. set @dynamicsql = @dynamicsql + ') as rowsize from ' + @Tablename + ' order by 2 desc'
  1.  
  1.  
  1. print (@dynamicsql)
  1.  
  1. END

 

 

如下截图所示,还真的有一些邮件记录的rowsize超级大,正常情况下,rowsize只有1122个字节左右大小,而mailitem_id=5146768 这条记录居然有1352285196字节,如果换算成大小的话SELECT 1352285196.0/1024/1024 ~=1290M, 真是无语了!!

 

 

EXEC sp_GetRowSize 'sysmail_mailitems', 'mailitem_id'

 

clip_image003

 

 

  原因倒也不复杂,就是生成邮件的SQL出现逻辑错误,导致邮件的Body变得无比巨大,导致msdb.dbo.sysmail_allitems变得非常大,与之相关的SQL语句IO性能变差,出现ASYNC_NETWORK_IO等待。其实以前也遇到过类似案例,请见SQL Server 2008 R2执行存储过程sp_MailItemResultSets引起大量PREEMPTIVE_OS_WAITFORSINGLEOBJEC等待,只是当时没有继续深挖Root Cause而已!

 

 

 

解决方案

 

那么如何解决这个问题呢? 很简单,就是删除表msdb.dbo.sysmail_allitems中的记录,让其Size变小。也可以删除那些mail_id非常大的记录。可以用下面脚本处理

 

  1. /******************************************************************************************************
  1.     Script Function            以下示例按条件删除数据库邮件系统中的电子邮件
  1. *******************************************************************************************************/
  1. DECLARE @GETDATE datetime 
  1. SET @GETDATE = GETDATE()-2; 
  1. EXECUTE msdb.dbo.sysmail_delete_mailitems_sp @sent_before = @GETDATE; 
  1. GO 

 

其实sysmail_delete_mailitems_sp中的逻辑也是去删除msdb.dbo.sysmail_allitems 中的记录,如下所示,在处理的过程中,需要在业务空闲的时候处理,否则会引起大量阻塞。

 

  1. DELETE 
  1. FROM msdb.dbo.sysmail_allitems
  1. WHERE ((@sent_before IS NULL)
  1. OR ( send_request_date < @sent_before))
  1. AND ((@sent_status IS NULL)
  1. OR (sent_status = @sent_status))

 

 

  1. CREATE PROCEDURE 
  1. sysmail_delete_mailitems_sp 
  1. @sent_before DATETIME = NULL,  -- sent before
  1.  
  1. @sent_status varchar(8) = NULL -- sent status
  1.  
  1. AS 
  1.    BEGIN 
  1.       SET @sent_status = LTRIM(RTRIM(@sent_status)) 
  1.       IF @sent_status = '' 
  1.       SET @sent_status = NULL 
  1.       IF ( (@sent_status IS NOT NULL) AND 
  1.       (LOWER(@sent_status collate SQL_Latin1_General_CP1_CS_AS) NOT IN ( 'unsent', 'sent', 'failed' 
  1.       , 'retrying') ) ) 
  1.       BEGIN 
  1.          RAISERROR(14266, -1, -1, '@sent_status', 'unsent, sent, failed, retrying') 
  1.          RETURN(1) -- Failure
  1.  
  1.       END 
  1.       IF ( @sent_before IS NULL AND @sent_status IS NULL ) 
  1.       BEGIN 
  1.          RAISERROR(14608, -1, -1, '@sent_before', '@sent_status') 
  1.          RETURN(1) -- Failure
  1.  
  1.       END 
  1. /* BEGIN ACTIVE SECTION (comment inserted by DPA) */ 
  1.       DELETE 
  1.       FROM msdb.dbo.sysmail_allitems 
  1.       WHERE ((@sent_before IS NULL) 
  1.       OR ( send_request_date < @sent_before)) 
  1.      AND ((@sent_status IS NULL) 
  1.       OR (sent_status = @sent_status))
  1. /* END ACTIVE SECTION (comment inserted by DPA) */ 
  1.          DECLARE @localmessage nvarchar(255) 
  1.          SET @localmessage = FORMATMESSAGE(14665, SUSER_SNAME(), @@ROWCOUNT) exec 
  1.          msdb.dbo.sysmail_logmailevent_sp @event_type=1, 
  1.          @description=@localmessage 
  1.       END 

 

原文链接:http://www.cnblogs.com/kerrycode/p/13729333.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号