题
最近,我不得不处理,我想象将是非常常见的一个问题:给出行的大(百万+)号的数据库表进行处理,并在各种机器/线程运行的各种处理器,如何安全地让每个处理器的实例来获得工作块(比如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表队列相关的问题:
排队中间件相关的问题:
您没有说你正在使用的数据库服务器,但也有几个选项。
的MySQL包括延伸到SQL99的INSERT
来限制被更新的行的数目。您可以指定每个工人一个独特的标记,更新行数,然后查询得到的是工人的批次。马克·所使用的UPDATE TOP
语法,但没有指定的数据库服务器。
另一种选择是指定用于锁定的表。不要使用同一个表中的数据,因为你不希望锁定它的阅读。你的锁表可能只需要一个单排,下一个ID需要的工作。一名工人锁定表,获取当前的ID,通过无论你的批量大小是递增的,更新表,然后释放锁。然后,它可以去查询数据表,并把它保留了行。此选项假定该数据表具有单调增加的ID,并且如果一个工人死亡或以其它方式不能完成一批量不是很容错。