我有一个数据库表,其中有大约50K行,每行表示需要完成的作业.我有一个程序从数据库中提取一个作业,做这个工作并将结果放回数据库. (这个系统现在运行)
现在我想允许多个处理任务执行任务,但确保没有任务完成两次(作为性能问题,不会导致其他问题).因为访问是通过一个新鲜的,我目前的目的是用一些看起来像这样的东西取代所说的鲜花
update tbl set owner=connection_id() where avalable and owner is null limit 1; select stuff from tbl where owner = connection_id();
BTW;工作人员的任务可能会在获得工作和提交结果之间留下联系.此外,我不期望数据库甚至接近成为瓶颈,除非我把这部分弄乱了(每分钟约5个工作)
有什么问题吗?有没有更好的方法来做到这一点?
注意:“Database as an IPC anti-pattern”在这里只是稍微apropos因为1)我没有做IPC(没有生成行的进程,它们现在已经存在)和2)为反模式描述的主要原因是它的结果在数据库中不必要的加载,因为进程等待消息(在我的情况下,如果没有消息,一切都可以关闭,因为一切都完成)
解决方法
以下是我过去成功使用的:
MsgQueue表模式
MsgId identity -- NOT NULL MsgTypeCode varchar(20) -- NOT NULL SourceCode varchar(20) -- process inserting the message -- NULLable State char(1) -- 'N'ew if queued,'A'(ctive) if processing,'C'ompleted,default 'N' -- NOT NULL CreateTime datetime -- default GETDATE() -- NOT NULL Msg varchar(255) -- NULLable
您的消息类型是您期望的 – 符合进程(插入)和进程(读取)之间的合同的消息,使用XML或其他选择的表示形式(JSON在某些情况下会很方便,实例).
然后0到n进程可以插入,0到n进程可以读取和处理消息,每个读取进程通常处理单个消息类型.可以运行多个流程类型的实例来进行负载平衡.
读者拉一个消息,并将状态更改为“A”ctive,而它的工作原理.完成后,将状态更改为“C”.根据您是否要保留审计跟踪,它可以删除消息. State =’N’的消息以MsgType / Timestamp顺序拉,所以在MsgType State CreateTime上有一个索引.
变化:
状态为“E”rror.
读者流程代码列.
状态转换的时间戳.
这提供了一个很好的,可扩展的,可见的,简单的机制来执行诸如你所描述的一些事情.如果你对数据库有一个基本的了解,那么它是非常笨重和可扩展的.
CREATE PROCEDURE GetMessage @MsgType VARCHAR(8) ) AS DECLARE @MsgId INT BEGIN TRAN SELECT TOP 1 @MsgId = MsgId FROM MsgQueue WHERE MessageType = @pMessageType AND State = 'N' ORDER BY CreateTime IF @MsgId IS NOT NULL BEGIN UPDATE MsgQueue SET State = 'A' WHERE MsgId = @MsgId SELECT MsgId,Msg FROM MsgQueue WHERE MsgId = @MsgId END ELSE BEGIN SELECT MsgId = NULL,Msg = NULL END COMMIT TRAN