Ich habe eine gespeicherte Prozedur, die eine ausgelastete Warteschlangentabelle abfragt, die zum Verteilen der Arbeit in unserem System verwendet wird. Die betreffende Tabelle hat einen Primärschlüssel für WorkID und keine Duplikate.
Eine vereinfachte Version der Abfrage lautet:
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)
Die #Types
Tabelle wird früher in der Prozedur ausgefüllt.
Wie gesagt, WorkTable
ist beschäftigt, und manchmal wird während der Ausführung dieser Abfrage I SUSPECT einer der Datensätze von einem Satz von Filtern in den WHERE
anderen verschoben . Dies geschieht insbesondere dann, wenn jemand mit der Arbeit an einem Element beginnt und W.InProgress
sich von 0 auf 1 ändert. In diesem Fall tritt eine doppelte Schlüsselverletzung auf, wenn ich versuche, der temporären Tabelle, in die diese Abfrage eingefügt wird, einen Primärschlüssel hinzuzufügen.
Ich habe im Abfrageplan, der generiert wurde, als der Fehler auftritt, bestätigt, dass keine Parallelität vorliegt, die Isolationsstufe ist READ COMMITTED
und keine doppelten Datensätze in der Quelltabelle vorhanden sind. Sie können auch sehen, dass es hier keine JOIN
s oder andere Möglichkeit gibt, kartesische Produkte zu erhalten.
Dies ist der anonymisierte Abfrageplan:
Die Frage ist, was verursacht die Duplikate und wie kann ich sie stoppen?
Ich denke READ COMMITTED
sollte hier funktionieren, ich brauche Sperren. Ich bin mir fast sicher, dass die Dupes auftreten, wenn sich das InProgress
Bit in einem Datensatz ändert, während ich abfrage. Ich weiß das, weil die Tabelle den Zeitpunkt dieser Änderung speichert und es innerhalb von Millisekunden ist, wenn ich den Fehler abfrage und erhalte.