如何快速关闭Microsoft SQL Server Service Broker的所有元素?

Noa*_*oah 2 sql-server service-broker

我们有一个应用程序,它使用Service Broker在SQL Server中创建队列和服务来处理数据库通信.该应用程序使用这些服务并正确发送/接收消息,但我现在想测试此应用程序的初始化阶段(它创建代理以及在幕后工作的存储过程).基本上,我需要以一定的频率删除代理元素,现在它真的很慢.

如果有帮助,我可以改变应用程序创建代理元素的方式 - 但这个问题与关闭所有内容更相关.

我用来关闭代理的代码是:

receive * from [dbo].[notify_initiator_queue]
alter queue [dbo].[notify_initiator_queue] with status = OFF
drop service [//DBNotifyService-Initiator]
drop queue [dbo].[notify_initiator_queue]
drop message types, contacts, etc...
Run Code Online (Sandbox Code Playgroud)

这在"drop service [// XF/DBNotifyService-Initiator]"上会挂起一段时间.有没有更快捷的方法来关闭和删除服务代理的所有或部分元素?

谢谢!

== ==更新

好吧,我花了一些时间,但下面的答案确实解决了这个问题.我想澄清可能遇到这个问题的其他人.

我的应用程序正确关闭所有服务,队列,合同和消息.关闭服务需要花费很长时间,因为应用程序中的一个bug会有一堆开放的对话.正在创建这些对话,用于发送消息,然后关闭:

END CONVERSATION @conversation with cleanup
Run Code Online (Sandbox Code Playgroud)

'with cleanup'位只关闭对话的本地端(想想,它允许服务器清理可能在另一端出错的任何对话).它不会关闭发送服务的另一端,因此会话保持打开状态.正常的对话应该结束:

END CONVERSATION @conversation
Run Code Online (Sandbox Code Playgroud)

这修复了app bug.但是,我在数据库中有几百万次破碎的对话.我可以像普通人一样丢弃数据库,或者我可以尝试弄清楚如何关闭数据库.要逐一关闭它们,需要:

declare @conversation uniqueidentifier 
while exists (select top 1 conversation_handle from sys.transmission_queue ) 
begin 
  set @conversation = (select top 1 conversation_handle from sys.transmission_queue )
  end conversation @conversation with cleanup 
end
Run Code Online (Sandbox Code Playgroud)

每个连接需要几毫秒(数百万的速度非常慢).如果我想快速关闭它们,请使用下面的答案并运行修改后的命令:

ALTER DATABASE [" + target.getTargetDbName() + "] SET NEW_BROKER WITH ROLLBACK IMMEDIATE;
Run Code Online (Sandbox Code Playgroud)

with rollback立即使所有连接都丢弃而不允许它们确保提交.文档说"将回滚所有未完成的事务,并且将立即断开与AdventureWorks2008R2示例数据库的任何其他连接." http://msdn.microsoft.com/en-us/library/bb522682.aspx

现在服务正在迅速下降,bug和开放的连接都消失了.

Rem*_*anu 5

原因很慢可能是因为这些元素使用SCH-S锁定,因为它们正在使用中,从而阻止了drop语句.典型的罪魁祸首是在后台运行的激活程序.通过检查活动监视器阻止原因或查看,可以快速调查此问题sys.dm_exec_requests.可以看到运行激活的程序sys.dm_broker_activated_tasks.

作为您可以尝试的解决方法ALTER DATABASE SET NEW_BROKER,它将删除所有现有会话,但不会删除队列/服务/合同/消息类型.它还将更改当前数据库service_broker_instance_id(如果您在路由中使用它,则很重要).通过删除所有会话,激活的过程应该自行关闭(如果它们被正确写入).

但我会建议采用不同的方法.您应该始终从干净的数据库启动并在干净的数据库上运行部署脚本,而不是让您的测试一次又一次地重复使用同一个数据库并处理所有错误的故障.这样您就不需要"删除"代码.请参阅版本控制和您的数据库.我们是一个干净数据库的数据库备份,并始终从那里开始,恢复它并部署您的应用程序,然后运行您的验证测试.