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 #Types
tabella 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 WHERE
all'altro. In particolare, ciò accade quando qualcuno inizia a lavorare su un elemento e le W.InProgress
modifiche 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 COMMITTED
e non ci sono record duplicati nella tabella di origine. Puoi anche vedere che non ci sono JOIN
altri 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 COMMITTED
dovrebbe funzionare qui, ho bisogno di blocco. Sono quasi sicuro che i duplicati si verifichino quando il InProgress
bit 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.