2009-06-02 31 views
36

Tengo una cola de pedidos a la que acceden varios procesadores de órdenes a través de un procedimiento almacenado. Cada procesador transfiere una identificación única que se utiliza para bloquear las siguientes 20 órdenes para su propio uso. El procedimiento almacenado luego devuelve estos registros al procesador de la orden sobre la que se actuará.SQL Server Process Queue Condición de carrera

Existen casos en que procesadores múltiples pueden recuperar el mismo registro 'OrderTable' en cuyo punto intentan operarlo simultáneamente. Esto, en última instancia, da lugar a errores lanzados más adelante en el proceso.

Mi siguiente línea de acción es permitir que cada procesador tome todas las órdenes disponibles y simplemente haga un ciclo completo de los procesadores, pero esperaba simplemente hacer esta sección de código seguro y permitir a los procesadores tomar registros cuando lo deseen.

Explicitamente: cualquier idea de por qué estoy experimentando esta condición de carrera y cómo puedo resolver el 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 
+4

@Keltex: Es evidente que él quiere saber cómo para volver a escribir este procedimiento almacenado para que no resulte en que dos procesadores procesen los mismos registros. – Welbog

Respuesta

48

Editar:

Busqué en Google para comprobar mi respuesta: "Processing Data Queues in SQL Server with READPAST and UPDLOCK". Han pasado años desde que leí y jugué con esta solución.

original:

Si se utiliza la sugerencia READPAST, a continuación, las filas cerradas se omiten. Has usado ROWLOCK, por lo que deberías evitar la escalada de bloqueo. También necesita UPDLOCK, como descubrí.

Así Proceso 1 cerraduras 20 filas, proceso 2 se llevarán los próximos 20, proceso 3 se toma en filas del 41 al 60, etc.

La actualización también se puede escribir así:

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

Actualizar, Oct 2011

Esto se puede hacer de forma más elegante con la cláusula OUTPUT si necesita un SELECT y una ACTUALIZACIÓN de una vez.

+0

Interesante ... Voy a intentarlo –

+0

Agregar los consejos adicionales realmente ayudaron. No más duplicados. Gracias. –

+0

Sé que esto es antiguo, pero es la sugerencia 'UPDLOCK' en la instrucción' UPDATE' forzando bloqueos de actualización (en lugar de bloqueos compartidos) mientras * leyendo * las filas para actualizar? En otras palabras, si no usa 'UPDLOCK', ¿es posible que exista una condición de carrera y dos instrucciones de actualización para seleccionar las mismas filas? –

Cuestiones relacionadas