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

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

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

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

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

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

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

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

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

~=1290M, 真是无语了!!

原因倒也不复杂,就是生成邮件的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非常大的记录。可以用下面脚本处理

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

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

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

SQL Server邮件相关SQL语句出现严重的ASYNC_NETWORK_IO等待事件案例的更多相关文章

  1. SQL SERVER如何通过SQL语句获服务器硬件和系统信息

    在SQL SERVER中如何通过SQL语句获取服务器硬件和系统信息呢?下面介绍一下如何通过SQL语句获取处理器(CPU).内存(Memory).磁盘(Disk)以及操作系统相关信息.如有不足和遗漏,敬 ...

  2. PowerDesigner反向数据库时遇到[Microsoft][ODBC SQL Server Driver][SQL Server]无法预定义语句。SQLSTATE = 37错误解决方法

    逆向工程中,有时会出现如下错误 ... [Microsoft][ODBC SQL Server Driver][SQL Server]无法预定义语句 SQLSTATE = 37000 解决方案: 1. ...

  3. SQL SERVER 复制相关存储过程

    适用于所有类型复制的过程 过程 说明 sp_addscriptexec 向发布的所有订阅服务器发布 Microsoft SQL Server 脚本(.sql 文件). sp_adjustpublish ...

  4. SQL Server Profiler监控执行语句

    SQL Server Profiler监控执行语句,这个功能主要用在实时的监控对数据库执行了什么操作,从而及时有效的跟踪系统的运行. 常规配置选项,名称.模板.保存到文件(可以复用). 事件选择,可以 ...

  5. SQL Server 日期相关

    原文:SQL Server 日期相关 原帖出处:http://blog.csdn.net/dba_huangzj/article/details/7657979 对于开发人员来说,日期处理或许简单,或 ...

  6. SQL Server 定时执行SQL语句的方法

    SQL SERVER 定时任务,你可以启动一下.不过要想更加直观的控制,直接写一个程序,定时执行你的存储过程. 1.设置“SQL Server 代理”(SQL Server Agent)服务随系统启动 ...

  7. SQL Server FOR XML PATH 语句的应用---列转行

    经常在论坛看到高手使用了 for xml path,由于是搜索一下,记录了详细的使用方法.在SQL Server中利用 FOR XML PATH 语句能够把查询的数据生成XML数据,下面是它的一些应用 ...

  8. SQL Server中的流控制语句

    begin···end 该语句定义sql代码块,通常在if和while语句中使用 declare @num int ; ; begin ; print 'hello word' end if···el ...

  9. SQL SERVER: 合并相关操作(Union,Except,Intersect)

    SQL SERVER: 合并相关操作(Union,Except,Intersect) use tempdb create table tempTable1 (id int primary key id ...

随机推荐

  1. 0基础算法基础学算法 第八弹 递归进阶,dfs第一讲

    最近很有一段时间没有更新了,主要是因为我要去参加一个重要的考试----小升初!作为一个武汉的兢兢业业的小学生当然要去试一试我们那里最好的几个学校的考试了,总之因为很多的原因放了好久的鸽子,不过从今天开 ...

  2. Vue源码分析之实现一个简易版的Vue

    目标 参考 https://cn.vuejs.org/v2/guide/reactivity.html 使用 Typescript 编写简易版的 vue 实现数据的响应式和基本的视图渲染,以及双向绑定 ...

  3. IdentityServer4中ResourceOwnerPassword模式获取accecc_token,并使用refresh_token刷新accecc_token

    一.IS4服务端配置 1.配置Client new Client { ClientId = "xamarin", ClientSecrets = { new Secret(&quo ...

  4. 类的加载,链接和初始化——1运行时常量池(来自于java虚拟机规范英文版本+本人的翻译和理解)

    加载(loading):通过一个特定的名字,找到类或接口的二进制表示,并通过这个二进制表示创建一个类或接口的过程. 链接:是获取类或接口并把它结合到JVM的运行时状态中,以让类或接口可以被执行 初始化 ...

  5. webpack跨域配置处理

    打开config->index.js 配置其中的proxyTable module.exports = { dev: { // Paths assetsSubDirectory: 'static ...

  6. 你不知道的JavaScript笔记----对象

    对象: 1.定义对象属性 属性描述符(也称为:数据描述符) Object.defineProperty(Object,PropertyName,{ value: 6, writable: true, ...

  7. robotframework自动化测试框架搭建及问题汇总

    1.安装python RF框架是基于python 的,所以一定要有python环境,python与rf存在兼容性问题,我安装的是python3.7.5,robotframework3.1.2. 选择添 ...

  8. 一文搞懂WordPress建站

    文章首发于:https://zouwang.vip/ 日日夜夜的等待,WordPress建站教程终于来了.本篇文章适用于第一次建站的小白,帮助你从零搭建起一个属于自己的网站,既然是从零,那么我就会带着 ...

  9. 用Python实现十大经典排序算法-插入、选择、快速、冒泡、归并等

    本文来用图文的方式详细讲解了Python十大经典排序算法 —— 插入排序.选择排序.快速排序.冒泡排序.归并排序.希尔排序.插入排序.桶排序.基数排序.计数排序算法,想要学习的你们,继续阅读下去吧,如 ...

  10. JVM学习第三天(JVM的执行子系统)之类加载机制

    好几天没有学习了,前几天因为导出的事情,一直在忙,今天继续学习, 其实今天我也遇到了一个问题,如果有会的兄弟可以评论留给我谢谢; 问题:fastJSON中JSONObject.parseObject做 ...