循环进程队列上的SQL Server争用条件,尽管将ROWLOCK
,READPAST
和UPDLOCK
提示与应用程序锁一起添加。
我有一个应用程序,其中多个应用程序服务器和多个进程运行" jobs"存储在SQL Server 2014数据库中的类似队列的表中。每隔x秒,每个进程查询表以查找要运行的新作业(如果该进程可用于执行作业)。需要在用户到用户的基础上以循环方式分配新的工作。问题是我当前的查询遇到竞争条件,因此多个进程作用于同一作业,导致输出表中出现重复的数据集。这是当前查询的样子:
EXEC sp_getapplock @Resource = 'GetJobAssignments', @LockMode = 'Exclusive', @LockOwner = 'Session';
BEGIN TRANSACTION;
WITH cte AS
(
SELECT TOP (@nMaxJobs) [JobId]
,[Owner]
,[Timeout]
,[StartTime]
,[Status]
,[userID]
, ROW_NUMBER() OVER (PARTITION BY [userID] ORDER BY [JobID]) AS [recID]
FROM [Jobs]
WITH (ROWLOCK, READPAST, UPDLOCK)
WHERE [Status] = 0 AND [Owner] is null
ORDER BY [recID], [userID]
)
UPDATE cte SET [Owner] = @owner, [Status] = 1;
COMMIT;
EXEC sp_releaseapplock @Resource = 'GetJobAssignments', @LockOwner = 'Session';
我尝试了ROWLOCK
,READPAST
,UPDLOCK
和XLOCK
的各种组合,但没有运气。在Session
和Transaction
设置中也可以使用和不使用applock。在查询的其他迭代中,我把事务隔离级别放到REPEATABLE READ
和SERIALIZABLE
,并且没有成功。
请记住,我既不是SQL也不是SQLServer专家,下一部分可能没有任何意义......我尝试在存储过程中执行此操作(就像现在一样),但在过去它也有使用dbContext.Database.ExecuteSqlCommand()
从EF5调用(它现在只是一个存储过程,是dbContext的一部分)。
这个当前的查询是对几个类似于此的问题的已知工作答案的混淆:
SQL Server Process Queue Race Condition
https://dba.stackexchange.com/questions/81791/strategies-for-checking-out-records-for-processing
除了我在这里提到的事情的基础研究之外,我对SQL Server中的策略非常不熟悉,以防止死锁/竞争条件。我可以在我的查询中尝试其他任何选项,或者是否存在可以检查的任何已知先决条件,这会阻止当前策略的运行?