У меня есть хранимая процедура, которая запрашивает таблицу занятых очередей, которая используется для распределения работы в нашей системе. У рассматриваемой таблицы есть первичный ключ на 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
бит записи меняется, когда я запрашиваю. Я знаю это, потому что в таблице хранится время этого изменения, и оно находится в пределах миллисекунд с момента, когда я запрашиваю и получаю ошибку.