【发布时间】:2011-04-08 04:31:33
【问题描述】:
给定一个充当队列的表,我怎样才能最好地配置表/查询,以便多个客户端同时从队列中处理?
例如,下表指示工作人员必须处理的命令。当worker完成后,它会将处理后的值设置为true。
| ID | COMMAND | PROCESSED |
| 1 | ... | true |
| 2 | ... | false |
| 3 | ... | false |
客户端可能会获得一个命令来处理,如下所示:
select top 1 COMMAND
from EXAMPLE_TABLE
with (UPDLOCK, ROWLOCK)
where PROCESSED=false;
但是,如果有多个工作人员,每个工作人员都会尝试获取 ID=2 的行。只有第一个会获得悲观锁,其余的将等待。然后其中一个将获得第 3 行等。
什么查询/配置可以让每个工作客户端分别获取不同的行并同时处理它们?
编辑:
有几个答案建议使用表本身记录进程中状态的变化。我认为这在单笔交易中是不可能的。 (即,如果在提交 txn 之前没有其他工作人员看到它,那么更新状态有什么意义?)也许建议是:
# start transaction
update to 'processing'
# end transaction
# start transaction
process the command
update to 'processed'
# end transaction
这是人们通常处理这个问题的方式吗?在我看来,如果可能的话,DB 会更好地处理这个问题。
【问题讨论】:
-
请指点我原来的,因为 SO 不推荐欺骗。
-
既然 Microsoft 消息队列 (MSMQ) 的形式已经可用于任何 Windows 服务器,为什么还要费力重新创建所有这些功能?使用可用的东西 - 不要不断重新发明轮子!
-
我不同意 marc_s。 MSMQ 为系统管理员和开发人员带来了极大的复杂性。数百万美元的项目失败了,因为他们使用了 MSMQ,但无法处理它的复杂性。如果没有令人信服的理由,您不应引入 MSMQ。
-
@marc_s:在不同的事务管理器中分离您的队列意味着在每个操作上进行两阶段提交以协调 SQL-MSMQ(即每秒数十/数百次操作与数万次单阶段提交)。将消息保存在 MSMQ 中并将状态保存在数据库中意味着 您不可能进行一致的备份。使用 MSMQ,您可以放松消息的可查询性。最后,MSMQ per store 有 2Gb 的限制,这在今天非常小,您可以轻松用完 MSMQ 存储空间,此时它只会滚动并死掉。
-
@Remus Rusanu:感谢那些有趣的见解——这些确实是 MSMQ 的一些严重缺陷.....
标签: sql sql-server database concurrency