最近,我不得不处理,我想象将是非常常见的一个问题:给出行的大(百万+)号的数据库表进行处理,并在各种机器/线程运行的各种处理器,如何安全地让每个处理器的实例来获得工作块(比如100项),而不彼此干扰?

我在同一时间得到一个大块的原因是出于性能的原因 - 我不想去数据库中的每个项目

有帮助吗?

解决方案

有几个方法 - 你可以令牌关联的每个处理器,并具有存储过程,其设定该令牌针对下一[n]的可用的项目;也许是这样的:

(注意 - 需要合适的隔离级;或许序列化:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

(编辑以固定TSQL)

UPDATE TOP (1000) WORK
SET [Owner] = @processor, Expiry = @expiry
OUTPUT INSERTED.Id -- etc
WHERE [Owner] IS NULL

您想也想在此超时(@expiry),这样,当一个处理器发生故障,你不会失去工作。您还会需要一个任务来清除的东西都是过去的Expiry所有者。

其他提示

可以有一个特殊的表排队工作起来,其中,所述消费者删除(或标记)作为被处理工作,或使用中间件排队溶液,像MSMQ或ActiveMQ的。

中间件都有它自己的一套问题,因此,如果可能的话,我会用一个特殊的表贴(保持尽可能小,希望只用一个ID,以便工人可以通过自己对获取信息的休息该数据库的其余部分,而不是锁定时间过长队列表达)。

您会填补这个表了定期和让处理器抢他们从上需要的东西。

在SQL表队列相关的问题:

队列使用表

工作了SQL查询一个优先级队列表

排队中间件相关的问题:

构建高性能和自动backupped队列

消息平台

您没有说你正在使用的数据库服务器,但也有几个选项。

的MySQL包括延伸到SQL99的INSERT来限制被更新的行的数目。您可以指定每个工人一个独特的标记,更新行数,然后查询得到的是工人的批次。马克·所使用的UPDATE TOP语法,但没有指定的数据库服务器。

另一种选择是指定用于锁定的表。不要使用同一个表中的数据,因为你不希望锁定它的阅读。你的锁表可能只需要一个单排,下一个ID需要的工作。一名工人锁定表,获取当前的ID,通过无论你的批量大小是递增的,更新表,然后释放锁。然后,它可以去查询数据表,并把它保留了行。此选项假定该数据表具有单调增加的ID,并且如果一个工人死亡或以其它方式不能完成一批量不是很容错。

scroll top