Ho una procedura memorizzata che richiede una tabella di coda occupata che viene utilizzata per distribuire il lavoro nel nostro sistema. La tabella in questione ha una chiave primaria su WorkID e nessun duplicato.
Una versione semplificata della query è:
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 #Typestabella viene popolata in precedenza nella procedura.
Come ho detto, WorkTableè occupato e, a volte, mentre questa query è in esecuzione, SOSPETTO uno dei record si sposta da un set di filtri WHEREall'altro. In particolare, ciò accade quando qualcuno inizia a lavorare su un elemento e le W.InProgressmodifiche da 0 a 1. Quando ciò accade, ottengo una violazione della chiave duplicata quando provo ad aggiungere una chiave primaria alla tabella temporanea in cui viene inserita questa query.
Ho confermato nel piano di query generato quando si verifica l'errore che non c'è parallelismo, il livello di isolamento è READ COMMITTEDe non ci sono record duplicati nella tabella di origine. Puoi anche vedere che non ci sono JOINaltri modi per ottenere prodotti cartesiani qui.
Questo è il piano di query anonimizzato:
La domanda è: cosa sta causando i duplicati e come posso farlo arrestare?
Penso che READ COMMITTEDdovrebbe funzionare qui, ho bisogno di blocco. Sono quasi sicuro che i duplicati si verifichino quando il InProgressbit su un record cambia mentre sto interrogando. Lo so perché la tabella memorizza l'ora di tale modifica ed è entro millisecondi di quando eseguo una query e ottengo l'errore.

