技术开发 频道

改进SQL Server服务代理的性能

  【IT168 技术文档】通过重用服务代理会话能够大大提升服务代理的性能。

  为每一个消息创建和关闭会话需要的开销大约是4X,而对于接收消息的性能提升大约能达到10X。Remus Rusanu在他发布在Reusing Conversations的博客上,谈到这个估值可能更大,并且还提出了一种重用会话的解决方案。

  我喜欢Remuss的解决方案,但其中有一个问题:我不愿意为每一个SPID创建不同的会话。如果我使用这种方法,就会有大量的会话打开,这样我还需要去关闭它们。在应用中,许多问题都可能触发一个服务代理消息的发送。而且通常情况下都会有大量的线程在同一时间对数据库进行访问。这就要求我们在实际环境使用Remuss的方法之前要对它进行优化,使之更灵活。我的想法是为我们应用中的每一个进程创建一个会话。并且在一定周期内,有一些会话会被关闭,也有些新的会话被创建。

  首先我先介绍一些关于安装服务代理的背景知识。我已经有2个队列和2个服务。每一个服务都在它自己的队列中。同时我有一个专门的消息类型,它用于将消息从源发送到目标位置。

  我的消息类型是MT_ObjectDelete,
  我的契约:CT_ObjectDelete,
  我的队列:Q_ObjectDelete_Source和Q_ObjectDelete_Destination,
  我的服务:Svc_ObjectDelete_Source和Svc_ObjectDelete_Destination,  
  
  另外我的另一个消息类型是MT_ConversationSwitch,它也是契约CT_ObjectDelete的一部分。

  为了存储我将生成的会话句柄,我会使用现有一个保存各种配置信息的表Setting。我已经添加了一些新的会话终端记录到表中。其中在Setting表中的查询名称是SSB_Session_Delete。我使用GetSystemSettingValue方法来查询Setting表得到配置值。发送数据的存储过程是这样的:

CREATE PROCEDURE [dbo].[SendDelete]
@FileName varchar(1024)
AS
DECLARE @DialogHandle uniqueidentifier
@msg XML,
@date nvarchar(100)
BEGIN
IF @msg IS NOT NULL
BEGIN
    
SET @DialogHandle = cast(dbo.GetSystemSettingValue('SSB_Session_Delete') as uniqueidentifier)
    
IF CAST(RAND()*100 AS INT) = 0 OR @DialogHandle IS NULL
BEGIN
IF @DialogHandle IS NOT NULL
SEND
ON CONVERSATION @DialogHandle
MESSAGE TYPE
[MT_ConversationSwitch]

BEGIN DIALOG CONVERSATION @dialogHandle
FROM SERVICE [Svc_ObjectDelete_Source]
TO SERVICE Svc_ObjectDelete_Destination
ON CONTRACT [CT_ObjectDelete_Multi];
        
UPDATE Setting
SET DefaultValue = @DialogHandle
WHERE SettingName = SSB_Session_Delete;
END;
SEND
ON CONVERSATION @dialogHandle
MESSAGE TYPE
[MT_ObjectDelete]
(
@msg)

IF @DialogHandle <> cast(dbo.GetSystemSettingValue(SSB_Session_Delete) as uniqueidentifier)
SEND
ON CONVERSATION @DialogHandle
MESSAGE TYPE
[MT_ConversationSwitch]
END
END
GO

  你可以从代码中看到,我通过查询获取当前的会话句柄。如果没有找到句柄,我会创建一个新句柄并将句柄值保存到我的Setting表中。如果CAST(RAND()*100 AS INT)返回0,我会使用现在会话中的MT_ConversationSwitch消息类型发送一条消息,它将触发接收程序的逻辑,终止该会话。在我终止该会话后,我再创建新的会话并将它存储在数据库中。

  然后我在该会话句柄上发送一条消息。接着我会再次检查Setting表,以确保我使用的值与表中的值是相匹配的。如果不匹配,我会认为另一个线程已经在相同的代码块中运行,然后关闭该会话,因为我不希望该会话继续存在。

0
相关文章