我有一个存储过程,用于查询用于在我们的系统中分配工作的繁忙队列表。有问题的表在 WorkID 上有一个主键并且没有重复项。
查询的简化版本是:
INSERT INTO #TempWorkIDs (WorkID)
SELECT
W.WorkID
FROM
dbo.WorkTable W
WHERE
(@bool_param = 0 AND
((W.InProgress = 0
AND ISNULL(W.UserID, -1) != @userid_param
AND (@bool_filtered = 0
OR W.TypeID IN (SELECT TypeID FROM #Types AS t)))
OR
(@bool_param = 1
AND W.InProgress = 1
AND W.UserID != @userid_param)
OR
(@Auto_Param = 0
AND W.UserID = @userid_param)))
OR
(@bool_param = 1 AND W.UserID = @userid_param)
OPTION
(RECOMPILE)
该#Types
表已在该过程的前面填充。
正如我所说,WorkTable
它很忙,有时在运行此查询时我怀疑其中一条记录正在从中的一组过滤器移动到另一组过滤器WHERE
。具体来说,当有人开始处理某个项目,并且W.InProgress
从 0 更改为 1 时,就会发生这种情况。发生这种情况时,当我尝试将主键添加到此查询插入的临时表中时,我遇到了重复键冲突。
我已经在错误发生时生成的查询计划中确认没有并行度,隔离级别为READ COMMITTED
,并且源表中没有重复记录。您还可以看到这里没有JOIN
s 或其他方法来获取笛卡尔积。
这是匿名查询计划:
问题是,是什么导致了重复,我怎样才能让它停止?
我认为READ COMMITTED
应该在这里工作,我需要锁定。我几乎可以肯定,当InProgress
我查询时记录上的位发生变化时,就会发生欺骗。我知道这一点是因为该表存储了该更改的时间,并且它在我查询并收到错误的几毫秒内。