Eu tenho um procedimento armazenado que consulta uma tabela de filas ocupadas que é usada para distribuir o trabalho em nosso sistema. A tabela em questão tem uma chave primária no WorkID e não há duplicatas.
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á em execução, SUSPEITO que um dos registros está se movendo de um conjunto de filtros WHERE
para outro. Especificamente, isso acontece quando alguém começa a trabalhar em um item e W.InProgress
muda 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 essa consulta está sendo 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
s ou outra maneira de obter produtos cartesianos aqui.
Este é o plano de consulta anônimo:
A questão é: o que está causando as duplicatas e como posso fazê-lo parar?
Acho que READ COMMITTED
deve funcionar aqui, preciso travar. Tenho quase certeza de que os enganos ocorrem quando o InProgress
bit em um registro muda enquanto estou consultando. Eu sei disso porque a tabela armazena a hora dessa alteração e está dentro de milissegundos de quando eu consulto e recebo o erro.