Eu tenho um procedimento armazenado que consulta uma tabela de fila ocupada que é usada para distribuir o trabalho em nosso sistema. A tabela em questão possui uma chave primária no WorkID e nenhuma duplicata.
Uma versão simplificada da consulta é:
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)
A #Types
tabela é preenchida anteriormente no procedimento.
Como eu disse, WorkTable
está ocupado e, às vezes, enquanto essa consulta está sendo executada, suspeito que um dos registros esteja se movendo de um conjunto de filtros WHERE
para outro. Especificamente, isso acontece quando alguém começa a trabalhar em um item e as W.InProgress
alterações de 0 para 1. Quando isso acontece, recebo uma violação de chave duplicada quando tento adicionar uma chave primária à tabela temporária na qual esta consulta está inserida.
Confirmei no plano de consulta gerado quando ocorre o erro que não há paralelismo, o nível de isolamento é READ COMMITTED
e não há registros duplicados na tabela de origem. Você também pode ver que não há JOIN
outra maneira de obter produtos cartesianos aqui.
Este é o plano de consulta anonimizado:
A questão é: o que está causando as duplicatas e como posso parar?
Eu acho que READ COMMITTED
deveria funcionar aqui, preciso travar. Estou quase certo de que as bobagens ocorrem quando o InProgress
bit em um registro muda enquanto estou consultando. Eu sei disso porque a tabela armazena o tempo dessa alteração e está dentro de milissegundos após a consulta e o erro.