Tengo un procedimiento almacenado que consulta una tabla de cola ocupada que se utiliza para distribuir el trabajo en nuestro sistema. La tabla en cuestión tiene una clave principal en WorkID y no tiene duplicados.
Una versión simplificada de la consulta es:
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)
La #Types
tabla se rellena anteriormente en el procedimiento.
Como dije, WorkTable
está ocupado y, a veces, mientras se ejecuta esta consulta, SUSPECTO que uno de los registros se mueve de un conjunto de filtros en el WHERE
otro. Específicamente, esto sucede cuando alguien comienza a trabajar en un elemento y los W.InProgress
cambios de 0 a 1. Cuando esto sucede, obtengo una violación de clave duplicada cuando intento agregar una clave principal a la tabla temporal en la que se inserta esta consulta.
He confirmado en el plan de consulta generado cuando ocurre el error que no hay paralelismo, el nivel de aislamiento es READ COMMITTED
, y no hay registros duplicados en la tabla de origen. También puede ver que no hay JOIN
otra forma de obtener productos cartesianos aquí.
Este es el plan de consulta anónimo:
La pregunta es, ¿qué está causando los duplicados y cómo puedo hacer que se detenga?
Creo que READ COMMITTED
debería funcionar aquí, necesito un bloqueo. Estoy casi seguro de que los engaños ocurren cuando el InProgress
bit en un registro cambia mientras estoy consultando. Sé esto porque la tabla almacena el tiempo de ese cambio y está dentro de milisegundos de cuando consulto y obtengo el error.