SQL Server,使用表作为队列

时间:2011-01-14 00:02:22

标签: sql sql-server sql-server-2008 queue

我正在使用SQL Server 2008 R2作为排队机制。我将项添加到表中,外部服务读取并处理这些项。这很好用,但缺少一件事 - 我需要机制,我可以尝试从表中选择一行,如果没有,则阻塞直到有(优选在特定的时间段内)。

有人可以建议我如何实现这一目标吗?

5 个答案:

答案 0 :(得分:8)

实现非池阻塞出列的唯一方法是WAITFOR (RECEIVE)。这意味着Service Broker队列,带来所有额外的开销。

如果您使用普通tables as queues,则无法实现非轮询阻止。您必须通过请求出列操作来轮询队列,如果它没有返回任何内容,请休眠并稍后再试。

我担心我会在这里不同意Andomar:虽然他的回答是一个普遍的问题'表中有任何行吗?'当涉及到排队时,由于重叠入队/出队的繁忙性质,检查这样的行是一个(几乎)保证在负载下的死锁。当使用表作为队列时,必须始终坚持基本的入队/出队操作,不要尝试花哨的东西。

答案 1 :(得分:7)

“自SQL Server 2005引入OUTPUT子句以来,使用表作为队列不再是一个难题”。关于如何做到这一点的好文章。

http://rusanu.com/2010/03/26/using-tables-as-queues/

答案 2 :(得分:2)

  

我需要机制,我可以尝试   从表中选择一行   并且,如果没有,则阻止直到   有(最好是具体的   一段时间)。

您可以每秒循环并检查新行:

while not exists (select * from QueueTable)
    begin
    wait for delay '00:01'
    end

免责声明:这不是我将用于生产系统的代码,但它可以满足您的要求。

答案 3 :(得分:1)

之前提出使用Service Broker的评论者可能得到了最好的答案。 Service Broker允许您在等待更多输入时实质上阻止。

如果Service Broker过度,您应该考虑采用不同的方法解决问题。你能提供你想要做的更多细节吗?

答案 4 :(得分:0)

让我分享一下我在这方面的经历,你会发现它很有帮助。

我的团队首先使用MSMQ事务队列来提供我们的异步服务(无论是IIS托管还是WAS)。我们遇到的最大问题是重负载下的MS DTC问题,例如100多条消息/秒负载;所有这一切都是一个缓慢的数据库操作,开始导致超时异常和MS DTC会让房子倒闭(如果事情变得很糟糕,交易实际上会丢失),虽然我们不是100%确定根直到今天,我们怀疑群集环境中的MS DTC存在一些严重问题。

因此,我们开始研究不同的解决方案。 Windows Server的Service Bus(Azure Service Bus的内部部署版本)看起来很有前途,但它是非事务性的,因此不符合我们的要求。

由于我们的交易要求,我们最终决定采用自己动手的方法,这是由构建Azure Service Bus的人员向我们建议的方法。从本质上讲,我们遵循Azure Worker Role模型来获取将通过某个队列提供的辅助角色;一个轮询阻止模型。

老实说,这比我们使用过的任何东西都好得多。这种服务的伪代码是:

hasMsg = true

while(true)

    if(!hasMsg)
         sleep

    msg = GetNextMessage

    if(msg == null)
        hasMsg = false
    else
        hasMsg = true

    Process(msg);

我们发现这种方式的CPU使用率明显较低(低于传统的WCF服务)。

当然,棘手的部分是处理交易。如果您希望从队列中读取多个服务实例,则需要在sql中使用read-past / updlock,并且还要让.net服务以一种滚动的方式登记到事务中。如果服务失败了。在这种情况下,除了常规队列之外,您还需要将重试/毒药队列作为表。