代码改变世界

SQL Server 2008 R2执行存储过程sp_MailItemResultSets引起大量PREEMPTIVE_OS_WAITFORSINGLEOBJEC等待

2020-03-24 23:44  潇湘隐者  阅读(...)  评论(...编辑  收藏


 

从监控工具DPA中发现一个数据库(SQL Server 2008 R2)的等待事件突然彪增,下钻分析发现数据库执行存储过程sp_MailItemResultSets时,引起了非常严重的等待(High Wait),而主要的等待事件为PREEMPTIVE_OS_WAITFORSINGLEOBJEC。 如下截图所示:

 

clip_image001

 

查询正在执行的SQL,发现会话正在执行下面SQL(存储过程sp_MailItemResultSets中的一个SQL语句),等待事件为ASYNC_NETWORK_IO。  

 

 
USE msdb;
go
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

 

 

 

关于ASYNC_NETWORK_IOPREEMPTIVE_OS_WAITFORSINGLEOBJEC的关系如下:

 

这个等待事件表示一个线程正在向外部客户端进程同步某个对象的数据,因此出现此种等待。而且通常和ASYNC_NETWORK_IO等待事件同时出现。根据我的观察,查询正在执行的SQL,等待事件为ASYNC_NETWORK_IO而并非PREEMPTIVE_OS_WAITFORSINGLEOBJEC

 

 

关于这个等待事件的更多详细信息,具体见链接PREEMPTIVE_OS_WAITFORSINGLEOBJECT,当前数据库版本为SQL Server 2008R2

 

Description:

 

This wait type is when a thread is calling the Windows WaitForSingleObject function for synchronization with an external client process that is communicating using that object.

 

Other information:

This wait type is commonly seen in conjunction(同时出现) with ASYNC_NETWORK_IO, depending on the network transport used to communicate with the   client, so to troubleshoot, follow the same steps as for ASYNC_NETWORK_IO.

 

Note that when a thread calls out to Windows, the thread changes from non-preemptive (SQL Server controls the thread) to preemptive (Windows controls the thread) mode. The thread’s state will be listed as RUNNING, as SQL Server doesn’t know what Windows is doing with the thread.

 

 

 

确实是一个非常奇怪的现象,然后我又去检查系统的应用日志,结果发现大量的错误:


clip_image002

 

错误信息比较奇怪,让人摸不着头脑,也没有看到有相关资料介绍,主要有下面两种错误:

 

1Database Engine Instance=xxxxx;Mail PID=7248;Error Message:The connection is not open.

 

2: Database Engine Instance=xxxxx;Mail PID=7248;Error Message:Exception of type 'System.OutOfMemoryException' was thrown.

 

 

验证SQL语句性能, 发现SQL语句的确非常慢,从执行计划来看,没有什么异常情况,而且这个也是系统数据库,不应该存在一些索引问题。

 

 

clip_image003

 

但是检查dbo.sysmail_mailitems表,发现此表记录数为2722,但是表的大小接近8G了。非常不正常。对比了其它几个数据库服务器,发现这个表非常小。检查邮件记录里面是否有大量附件。也没有发现有大量附件。


处理问题的时候,没去定位是那条或那些记录占用了大量空间。急着解决问题,放弃分析这些情况了。可惜了!

 

clip_image004

 

clip_image005

 

 

官方也没有相关资料,只能猜测是因为dbo.sysmail_mailitems的大小引起了性能问题,然后我尝试用下面SQL清理这个表的记录

 

/******************************************************************************************************
    Script Function        :    以下示例删除数据库邮件日志中所有失败的电子邮件
*******************************************************************************************************/
 
 
EXECUTE msdb.dbo.sysmail_delete_mailitems_sp   
    @sent_status = 'failed'
GO 
 
/******************************************************************************************************
    Script Function        :    以下示例删除数据库邮件系统中的所有电子邮件
*******************************************************************************************************/
DECLARE @GETDATE datetime  
SET @GETDATE = GETDATE();  
EXECUTE msdb.dbo.sysmail_delete_mailitems_sp @sent_before = @GETDATE;  
GO  
 

 

最后清理过后验证发现,这个存储过程的确非常快了,数据库中该等待事件直接消失了。系统应用日志中关于Mail PID的错误也消失了。后续观察发现,这个表也变得特别小了,完全没有之前那么大了。

 

 

clip_image006