Condizione di gara della coda di elaborazione di SQL Server

Ho una coda ordini a cui si accede da più processori di ordini attraverso una stored procedure. Ogni processore passa in un ID univoco che viene utilizzato per bloccare i prossimi 20 ordini per il proprio uso. La stored procedure restituisce quindi questi record al processore degli ordini su cui agire.

Ci sono casi in cui più processori sono in grado di recuperare lo stesso record “OrderTable” e in quel momento cercano di operare simultaneamente su di esso. Questo alla fine si traduce in errori lanciati più avanti nel processo.

La mia prossima linea d’azione è quella di consentire ad ogni processore di afferrare tutti gli ordini disponibili e di arrotondare semplicemente i processori, ma speravo semplicemente di rendere sicura questa sezione del codice e consentire ai processori di catturare i record quando vogliono.

Così esplicitamente – Qualche idea sul perché sto vivendo questa condizione di gara e su come posso risolvere il problema.

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 

Modificare:

Ho cercato su google per verificare la mia risposta: “Elaborazione delle code dati in SQL Server con READPAST e UPDLOCK” . Sono passati anni da quando ho letto e giocato con questa soluzione.

Originale:

Se si utilizza l’hint READPAST, le righe bloccate vengono saltate. Hai usato ROWLOCK in modo da evitare l’escalation dei blocchi. Hai anche bisogno di UPDLOCK, come ho scoperto.

Quindi il processo 1 blocca 20 righe, il processo 2 prenderà il successivo 20, il processo 3 richiede le righe da 41 a 60, ecc

L’aggiornamento può anche essere scritto in questo modo:

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

Aggiorna, ott 2011

Questo può essere fatto in modo più elegante con la clausola OUTPUT se hai bisogno di un SELECT e di un UPDATE in un colpo solo.

È ansible utilizzare Service Broker. Inoltre puoi utilizzare sp_getapplock per serializzare l’accesso alle tue righe, eliminando le condizioni di gara:

“Assistere la concorrenza creando i propri blocchi (Mutex in SQL)” http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx