2009-10-06 10 views
29

He visto muchos ejemplos de la sugerencia de HOLDLOCK que se usa en combinación con UPDLOCK (like this). Sin embargo, Microsoft's documentation para estas sugerencias hacen que parezca que HOLDLOCK debe ser redundante, ya que UPDLOCK ya persiste en el bloqueo hasta el final de la transacción. (También parece decir que HOLDLOCK solo se aplica a los bloqueos compartidos de todos modos.)¿Qué efecto tiene HOLDLOCK en UPDLOCK?

¿Cómo afecta HOLDLOCK a la consulta, si es que lo hace?

Respuesta

59

Tiene un gran impacto.

El bloqueo de actualización toma un bloqueo de actualización en la fila, actualización de intención en la página y un bloqueo compartido en la tabla/base de datos.

Esto no impide que otras consultas accedan a los datos dentro de la tabla, ya que los bloqueos en la página/base de datos son meramente bloqueos compartidos. Simplemente no pueden chocar bloqueos contra la fila/página/tabla individual al intentar realizar una operación que podría contradecir los bloqueos. Si eso ocurría, la solicitud se pondría detrás de las cerraduras actuales y esperaría a que estuviera disponible antes de que pudiera continuar.

Al usar holdlock, la consulta está siendo forzada a ser serializada, bloqueando la tabla exclusivamente hasta que se complete la acción. Esto evita que alguien lea la tabla a menos que se use la pista nolock, permitiendo una lectura potencialmente sucia.

Para ver el efecto, genere una tabla de ejemplo 'foo' y coloque algunos datos de basura en ella.

begin tran 

select * from foo with (updlock) 
where tableid = 1 
-- notice there is no commit tran 

abrir otra ventana y tratar:

select * from foo 

Las filas regresan, ahora confirman la transacción búsqueda original. Vuelva a ejecutar es alterado para usar holdlock así:

begin tran 

select * from foo with (updlock, holdlock) 
where tableid = 1 

volver a la otra ventana y tratar de seleccionar los datos de nuevo, la consulta no devolver valores, ya que está bloqueado por el bloqueo exclusivo. Confirme la transacción en la primera ventana y los resultados en la segunda consulta aparecerán porque ya no está bloqueada.

La prueba final es utilizar el nolock, ejecute la transacción de nuevo utilizando updlock y holdlock. a continuación, ejecute el siguiente en la segunda ventana:

select * from foo (nolock) 

Los resultados van a volver de forma automática, ya que han aceptado el riesgo de una lectura sucia (lectura no confirmada).

Por lo tanto, se considera que tiene un gran impacto, ya que obliga a serializar las acciones contra esa tabla que podrían ser lo que desea (dependiendo de la actualización) o creará un cuello de botella muy grande en esa tabla . Si todos hicieran eso en una mesa ocupada con transacciones de larga ejecución, entonces causaría demoras significativas dentro de una aplicación.

Al igual que con todas las funciones de SQL, cuando se usan correctamente pueden ser potentes, pero el uso incorrecto de una característica/sugerencia puede causar problemas importantes. Prefiero usar consejos como último recurso para cuando tengo que anular el motor, no como un enfoque predeterminado.

Editar como solicitado: Probado en SQL 2005, 2008, 2008R2 (All Enterprise): todos instalados en configuraciones predeterminadas, base de datos de prueba creada utilizando todos los valores predeterminados (solo ingresó el nombre del DB solamente).

+0

buena respuesta, gracias – marijne

+0

buena explicación, eso ayuda mucho! – Mercurybullet

+0

@Darren: he retrocedido la edición que ha realizado, ningún bloqueo no es el predeterminado y el segundo no debe tomar un bloqueo de actualización. – Andrew

12

de la respuesta de Andrew es correcta de acuerdo con la documentación de MSDN, sin embargo he probado contra 2008R2 y 2012 y no estoy viendo este comportamiento así que por favor ponerse a prueba

El comportamiento que estoy viendo es la siguiente:

Primero ejecute esto en una base de datos de reproducción.

CREATE TABLE [dbo].[foo](
    [tableid] [int] IDENTITY(1,1) NOT NULL, 
    [Col2] [varchar](100) NOT NULL, 
    CONSTRAINT [PK_foo] PRIMARY KEY CLUSTERED 
    (
     [tableid] ASC 
    ) 
) 

... y poner un par de filas en

Ahora pega este código en dos fichas de consulta (cambiar el texto 'pestaña uno' en la pestaña de dos):.

begin tran 

select * from foo with (UPDLOCK, HOLDLOCK) 
where tableid = 1 

UPDATE foo SET Col2 = 'tab one' 
where tableid = 1 

commit tran 

Y poner esto en otra pestaña :

select * from foo 
where tableid = 1 
  1. Asegúrate de apuntar a la base de datos de reproducción donde está la tabla.

  2. Resalte todo antes de la instrucción de actualización en la pestaña y ejecutar.

  3. Haz lo mismo en pestaña 2, verás que la pestaña 2 NO se completará y aún se está ejecutando.

  4. Ahora ejecutar la sencilla SELECT en pestaña 3en mi entorno que complete.

  5. Resalte la instrucción de actualización en la pestaña y ejecutarlo (no hago el comprometerse todavía), verá la pestaña 2 se TODAVÍA ejecutando.

  6. proceda a ejecutar el commit en ficha 1 ... pestaña 2 ahora completar la selecta ... se puede ejecutar el resto.

+0

¿Con qué versión de SQL Server se ejecutó esta versión? si 2012, el comportamiento puede cambiar, pero el bloqueo de 2005/2008/2008R2 lo forzaría a entrar en modo serializable y bloquearía cualquier otra cosa que no tenga un bloqueo compartido, que es lo que la selección 'simple' intentará emitir. – Andrew

+1

Otra posibilidad, tiene activado el aislamiento basado en versiones de fila: cuando el aislamiento basado en versiones de fila está en su lugar, la selección 'simple' no emitirá un bloqueo compartido, solo un bloqueo Sch-S, que evitaría que se bloquee, aunque ese nivel de aislamiento no es el predeterminado en 2008. Será interesante identificar la diferencia en las pruebas. – Andrew

+0

@Andrew and Darren: edite sus publicaciones respectivas y observe en qué versiones de SQL Server * ha probado * sus soluciones. También se apreciarán los enlaces que describan cualquier cambio en el comportamiento predeterminado (o cualquier configuración que haya realizado) =) –

Cuestiones relacionadas