2009-06-02 7 views
36

Ich habe eine Auftragswarteschlange, auf die mehrere Auftragsprozessoren über eine gespeicherte Prozedur zugreifen. Jeder Prozessor übergibt eine eindeutige ID, mit der die nächsten 20 Aufträge für die eigene Verwendung gesperrt werden. Die gespeicherte Prozedur gibt diese Datensätze dann an den Auftragsprozessor zurück, der bearbeitet werden soll.SQL Server Prozess Queue Race-Bedingung

Es gibt Fälle, in denen mehrere Prozessoren in der Lage sind, denselben 'OrderTable'-Datensatz abzurufen, zu welchem ​​Zeitpunkt sie versuchen, gleichzeitig daran zu arbeiten. Dies führt letztendlich zu Fehlern, die später im Prozess ausgelöst werden.

Meine nächste Vorgehensweise besteht darin, dass jeder Prozessor alle verfügbaren Befehle ergreift und nur die Prozessoren abrundet, aber ich hoffte, diesen Teil des Code-Threads sicher zu machen und es den Prozessoren zu ermöglichen, Datensätze zu erfassen, wann immer sie möchten.

Also Explizit - Jede Idee, warum ich diese Race Condition erfahre und wie ich das Problem lösen kann.

BEGIN TRAN 
    UPDATE OrderTable WITH (ROWLOCK) 
    SET  ProcessorID = @PROCID 
    WHERE OrderID IN (SELECT TOP (20) 
             OrderID 
           FROM OrderTable WITH (ROWLOCK) 
           WHERE ProcessorID = 0) 
COMMIT TRAN 


SELECT OrderID, ProcessorID, etc... 
FROM OrderTable 
WHERE ProcessorID = @PROCID 
+4

@Keltex: Offensichtlich will er wissen, wie um diese gespeicherte Prozedur neu zu schreiben, so dass dies nicht dazu führt, dass zwei Prozessoren denselben Datensatz verarbeiten. – Welbog

Antwort

48

Edit:

Ich googeln meine Antwort zu überprüfen: "Processing Data Queues in SQL Server with READPAST and UPDLOCK". Es ist Jahre her, seit ich über diese Lösung gelesen habe und mit ihr gespielt habe.

Original:

Wenn Sie den READPAST Hinweis verwenden, dann sind gesperrte Zeilen übersprungen. Sie haben ROWLOCK verwendet, daher sollten Sie eine Sperreskalation vermeiden. Du brauchst auch UPDLOCK, wie ich herausgefunden habe.

verarbeiten So 1 Schlösser 20 Zeilen, Verfahren 2 wird die nächsten 20, nehmen Prozess wie diese Zeilen 3 41 bis 60, usw.

Das Update kann auch geschrieben nimmt:

UPDATE TOP (20) 
    foo 
SET 
    ProcessorID = @PROCID 
FROM 
    OrderTable foo WITH (ROWLOCK, READPAST, UPDLOCK) 
WHERE 
    ProcessorID = 0 

Refresh, Okt 2011

Dies kann elegant mit der OUTPUT-Klausel durchgeführt werden, wenn Sie ein SELECT und ein UPDATE auf einmal benötigen.

+0

Interessant ... Ich werde es versuchen –

+0

Das Hinzufügen der zusätzlichen Hinweise hat wirklich geholfen. Keine Duplikate mehr. Vielen Dank. –

+0

Ich weiß, das ist alt, aber ist der 'UPDLOCK'-Hinweis in der' UPDATE'-Anweisung, die Aktualisierungssperren erzwingt (anstelle von gemeinsamen Sperren), während * die * zu aktualisierenden Zeilen * gelesen werden? Mit anderen Worten, wenn Sie nicht "UPDLOCK" verwenden, ist es möglich, dass eine Race-Bedingung existiert und zwei update-Anweisungen die gleichen Zeilen auswählen? –