44 votes

Condition de concurrence de la file d'attente de processus SQL Server

J'ai un ordre de la file d'attente qui est accessible par plusieurs processeurs moyen d'une procédure stockée. Chaque processeur passe dans un ID unique qui est utilisé pour verrouiller les 20 prochaines commandes pour son propre usage. La procédure stockée renvoie alors ces dossiers à l'ordre du processeur à l'ordre du jour.

Il y a des cas où plusieurs processeurs sont en mesure de récupérer la même "OrderTable' enregistrement à quel point ils essayent de les opérer sur elle. Cette situation entraîne des erreurs en cours de levée plus tard dans le processus.

Mon prochain cours de l'action est de permettre à chaque processeur de saisir toutes les commandes disponibles et tout autour de robin des processeurs, mais j'espérais tout simplement faire de cette section de code thread-safe et permettre aux établissements de transformation de saisir des enregistrements à chaque fois que qu'ils aiment.

Donc Explicitement - une idée de pourquoi je suis en train de vivre cette "race condition" et comment je peux résoudre le problème.

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

56voto

gbn Points 197263

Edit:

J'ai googlé pour vérifier ma réponse: "le Traitement des Files d'attente de Données dans SQL Server avec READPAST et UPDLOCK". Cela fait des années depuis que j'ai lu et joué avec cette solution.

Origine:

Si vous utilisez l'indicateur READPAST, puis verrouillé lignes sont ignorés. Vous avez utilisé le VERROU de sorte que vous devriez éviter l'escalade de verrous. Vous avez également besoin d'UPDLOCK, que j'ai trouvé.

Donc, processus 1 verrous de 20 lignes, processus 2 va passer à la prochaine 20, processus 3 prend les lignes 41 à 60, etc

La mise à jour peut aussi être écrit comme ceci:

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

Actualiser, Oct 2011

Cela peut être fait de manière plus élégante avec la SORTIE de la clause si vous avez besoin d'une sélection et une mise à JOUR d'un seul coup.

6voto

AlexKuznetsov Points 9555

Vous pouvez utiliser Service Broker. Vous pouvez également utiliser sp_getapplock pour sérialiser l'accès à vos lignes - cela éliminera les conditions de concurrence:

"Aide à la concurrence en créant vos propres verrous (mutex dans SQL)" http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X