2010-01-25 12 views
8

Necesito seleccionar primero (digamos) 10000 filas en la base de datos y devolverlas. Es posible que haya más clientes que realicen esta operación al mismo tiempo. Se me ocurrió esta consulta:¿La actualización tiene una operación atómica de selección anidada?

update v set v.batch_Id = :batchId 
    from tblRedir v 
    inner join (
     select top 10000 id 
      from tblRedir 
      where batch_Id is null 
      order by Date asc 
    ) v2 on v.id=v2.id 

Es una operación que consta de actualización y selección anidada. Ambas consultas funcionan en la misma tabla (tblRedir). La idea es que las filas son primero marcadas por una BATCHID única y luego devueltos a través de

select * from tblRedir where batch_id = :batchId 

(el BatchID es un identificador único (por ejemplo, marca de tiempo o GUID) para cada esta actualización)

Mi pregunta:

pensé que la actualización de la operación con anidada seleccione es atómico - que significa que cada cliente recibe su propio conjunto de datos que es único (no hay otro cliente recibió un subconjunto de sus datos).

Sin embargo parece que estoy equivocado - en algunos casos, hay clientes que no reciben los datos, ya que probablemente primera tanto ejecutar el selecto y entonces ambos ejecutar la actualización (por lo que el primer cliente no tiene marcada filas).

¿Es esta operación atómica o no?


trabajo con el servidor SQL 2005. La consulta se ejecuta a través de la misma familia NHibernate

session.CreateSQLQuery('update....') 

Respuesta

5

SELECT lugares bloqueos compartidos en las filas leídas que luego se pueden levantar en READ COMMITED modo de aislamiento.

UPDATE coloca los bloqueos de actualización promocionados posteriormente a bloqueos exclusivos. No se levantan hasta el final de la transacción.

Debe hacer que los bloqueos se retengan tan pronto como se colocan.

Puede hacerlo realizando el nivel de aislamiento de transacción REPEATABLE READ que retendrá los bloqueos compartidos hasta el final de la transacción y evitará que UPDATE bloqueen estas filas.

Alternativamente, puede volver a escribir la consulta como esta:

WITH q AS 
     (
     SELECT TOP 10000 * 
     FROM mytable WITH (ROWLOCK, READPAST) 
     WHERE batch_id IS NULL 
     ORDER BY 
       date 
     ) 
UPDATE q 
SET  batch_id = @myid 

, que acaba de saltar las filas bloqueadas.

+0

Thx por su respuesta. He intentado con la alternativa ('con q como ...') y parece que READPAST no se puede usar con HOLDLOCK. Probé el nivel de aislamiento 'leer confirmado', 'lectura repetible' y en ambos casos el servidor sql se queja 'Solo se puede especificar el bloqueo de LECTURA en LECTURA COMPROMETIDA o LECTURA REPETIBLE niveles de aislamiento'. ¿La consulta es correcta incluso sin HOLDLOCK? – stej

+0

'@ stej': No creo que' SQL Server' separe partes 'SELECT' y' UPDATE' en este caso, así que sí, los bloqueos de actualización se colocarán automáticamente. Puede quitar el 'HOLDLOCK'. – Quassnoi

+0

Gracias. Lo intenté, parece que funciona. En algunos casos, hubo muchos bloqueos, pero de repente no hay ninguno, es difícil reproducirlo.En caso de que pueda describirlo de alguna manera, enviaré una nueva pregunta. – stej

Cuestiones relacionadas