【发布时间】:2014-08-01 05:09:15
【问题描述】:
我使用带有内部激活的 SQL Service Broker 将作业列表移动到内部激活的存储过程以完成,而无需让主线程/请求者等待实际的单个作业完成。本质上,我正在尝试释放 UI 线程。问题是,我将 2000 多个作业传递给服务代理,消息在大约 25 分钟内到达队列并释放 UI,但是即使一个小时后,它也只完成了近 600 多个作业 我使用下面的查询来计算等待完成的数量,它看起来非常慢
SELECT COUNT(*)
FROM [HMS_Test].[dbo].[HMSTargetQueueIntAct]
WITH(NOLOCK)
下面是我为您的参考激活存储过程。有人可以看看,让我知道这有什么问题吗?如何让 SB 快速完成队列中的这些项目?在此先感谢:)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_SB_HMSTargetActivProc]
AS
BEGIN
DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
DECLARE @RecvReqMsg NVARCHAR(1000);
DECLARE @RecvReqMsgName sysname;
DECLARE @XMLPtr int
DECLARE @ExecuteSQL nvarchar(1000)
DECLARE @CallBackSP nvarchar(100)
DECLARE @CallBackSQL nvarchar(1000)
DECLARE @SBCaller nvarchar(50)
DECLARE @LogMsg nvarchar(1000)
WHILE (1=1)
BEGIN
BEGIN TRANSACTION;
WAITFOR
( RECEIVE TOP(1)
@RecvReqDlgHandle = conversation_handle,
@RecvReqMsg = message_body,
@RecvReqMsgName = message_type_name
FROM HMSTargetQueueIntAct
), TIMEOUT 5000;
IF (@@ROWCOUNT = 0)
BEGIN
ROLLBACK TRANSACTION;
BREAK;
END
IF @RecvReqMsgName = N'//HMS/InternalAct/RequestMessage'
BEGIN
DECLARE @ReplyMsg NVARCHAR(100);
SELECT @ReplyMsg = N'<ReplyMsg>ACK Message for Initiator service.</ReplyMsg>';
SEND ON CONVERSATION @RecvReqDlgHandle
MESSAGE TYPE
[//HMS/InternalAct/ReplyMessage]
(@ReplyMsg);
EXECUTE sp_xml_preparedocument @XMLPtr OUTPUT, @RecvReqMsg
SELECT @ExecuteSQL = ExecuteSQL
,@CallBackSP = CallBackSP
,@SBCaller = SBCaller
FROM OPENXML(@XMLPtr, 'RequestMsg/CommandParameters', 1)
WITH (ExecuteSQL nvarchar(1000) 'ExecuteSQL'
,CallBackSP nvarchar(1000) 'CallBackSP'
,SBCaller nvarchar(50) 'SBCaller'
)
EXEC sp_xml_removedocument @XMLPtr
IF ((@ExecuteSQL IS NOT NULL) AND (LEN(@ExecuteSQL)>0))
BEGIN
SET @LogMsg='ExecuteSQL:' + @ExecuteSQL
EXECUTE(@ExecuteSQL);
SET @LogMsg='ExecuteSQLSuccess:' + @ExecuteSQL
EXECute sp_LogSystemTransaction @SBCaller,@LogMsg,'SBMessage',0,''
END
IF ((@CallBackSP IS NOT NULL) AND (LEN(@CallBackSP)>0))
BEGIN
SET @CallBackSQL = @CallBackSP + ' @Sender=''sp_SB_HMSTargetActivProc'', @Res=''' + @ExecuteSQL + ''''
SET @LogMsg='CallBackSQL:' + @CallBackSQL
EXECute sp_LogSystemTransaction @SBCaller,@LogMsg,'SBMessage',0,''
EXECUTE(@CallBackSQL);
END
END
ELSE IF @RecvReqMsgName = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
BEGIN
SET @LogMsg='MessageEnd:';
END CONVERSATION @RecvReqDlgHandle WITH CLEANUP;
END
ELSE IF @RecvReqMsgName = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
BEGIN
DECLARE @message_body VARBINARY(MAX);
DECLARE @code int;
DECLARE @description NVARCHAR(3000);
DECLARE @xmlMessage XML;
SET @xmlMessage = CAST(@RecvReqMsg AS XML);
SET @code = (
SELECT @xmlMessage.value(
N'declare namespace
brokerns="http://schemas.microsoft.com/SQL/ServiceBroker/Error";
(/brokerns:Error/brokerns:Code)[1]',
'int')
);
SET @description = (
SELECT @xmlMessage.value(
'declare namespace
brokerns="http://schemas.microsoft.com/SQL/ServiceBroker/Error";
(/brokerns:Error/brokerns:Description)[1]',
'nvarchar(3000)')
);
IF (@code = -8462)
BEGIN
SET @LogMsg='MessageEnd:';
--EXECute sp_LogSystemTransaction @SBCaller,@LogMsg,'SBMessage',0,'';
END CONVERSATION @RecvReqDlgHandle WITH CLEANUP;
END
ELSE
BEGIN
SET @LogMsg='ERR:' + @description + ' ' + CAST(@code AS VARCHAR(20));
EXECute sp_LogSystemTransaction @SBCaller,@LogMsg,'SBError',0,'';
END CONVERSATION @RecvReqDlgHandle;
END
END
COMMIT TRANSACTION;
END
END
【问题讨论】:
-
一开始队列很慢。花了将近一个小时来浏览 600 多条消息,还剩下将近 2000 条。我在其中一个表上运行了一个选择查询,该表将由上述代码执行的 SQL 更新,并得到一个错误重新锁定,我用 (nolock) 重新运行了查询,我得到了结果,同时,队列中的所有消息也都消失了,作业也完成了。我无法解释发生了什么,但需要解释为什么一开始会有很大的延迟并避免它。
标签: sql-server multithreading stored-procedures service-broker