Confundido acerca de UPDLOCK, HOLDLOCK

89

Mientras investigaba el uso de Table Hints , me encontré con estas dos preguntas:

Las respuestas a ambas preguntas dicen que cuando se usan (UPDLOCK, HOLDLOCK), otros procesos no podrán leer datos en esa tabla, pero yo no vi esto. Para probar, creé una tabla e inicié dos ventanas SSMS. Desde la primera ventana, ejecuté una transacción que seleccionó de la tabla usando varias sugerencias de tabla. Mientras se ejecutaba la transacción, desde la segunda ventana ejecuté varias declaraciones para ver cuál se bloquearía.

La mesa de prueba:

CREATE TABLE [dbo].[Test](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Desde la ventana 1 de SSMS:

BEGIN TRANSACTION

SELECT * FROM dbo.Test WITH (UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:10'

COMMIT TRANSACTION

Desde la ventana 2 de SSMS (ejecutó uno de los siguientes):

SELECT * FROM dbo.Test
INSERT dbo.Test(Value) VALUES ('bar')
UPDATE dbo.Test SET Value = 'baz' WHERE Value = 'bar'
DELETE dbo.Test WHERE Value= 'baz'

Efecto de diferentes sugerencias de tabla en declaraciones ejecutadas en la Ventana 2:

           (UPDLOCK)       (HOLDLOCK)    (UPDLOCK, HOLDLOCK)    (TABLOCKX)
---------------------------------------------------------------------------
SELECT    not blocked      not blocked       not blocked         blocked
INSERT    not blocked        blocked           blocked           blocked
UPDATE      blocked          blocked           blocked           blocked
DELETE      blocked          blocked           blocked           blocked

¿Entendí mal las respuestas dadas en esas preguntas o cometí un error en mis pruebas? Si no es así, ¿por qué usarías (UPDLOCK, HOLDLOCK)o (HOLDLOCK)solo?


Más explicación de lo que estoy tratando de lograr:

Me gustaría seleccionar filas de una tabla y evitar que los datos de esa tabla se modifiquen mientras los estoy procesando. No estoy modificando esos datos y me gustaría permitir que se realicen lecturas.

Esta respuesta dice claramente que (UPDLOCK, HOLDLOCK)bloqueará las lecturas (no lo que quiero). Los comentarios sobre esta respuesta implican que es lo HOLDLOCKque impide las lecturas. Para intentar comprender mejor los efectos de las sugerencias de la tabla y ver si UPDLOCKsolo haría lo que quería, hice el experimento anterior y obtuve resultados que contradicen esas respuestas.

Actualmente, creo que eso (HOLDLOCK)es lo que debería usar, pero me preocupa haber cometido un error o haber pasado por alto algo que volverá a morderme en el futuro, de ahí esta pregunta.

Jeff Ogata
fuente

Respuestas:

102

¿Por qué UPDLOCK bloqueará selecciones? La Matriz de compatibilidad de cerraduras se muestra claramente Npara la contención S / U y U / S, como en No Conflict .

En cuanto a la sugerencia de HOLDLOCK, la documentación dice:

HOLDLOCK: Equivale a SERIALIZABLE. Para obtener más información, consulte SERIALIZABLE más adelante en este tema.

...

SERIALIZABLE: ... El escaneo se realiza con la misma semántica que una transacción que se ejecuta en el nivel de aislamiento SERIALIZABLE ...

y el tema Nivel de aislamiento de transacciones explica qué significa SERIALIZABLE:

Ninguna otra transacción puede modificar los datos leídos por la transacción actual hasta que se complete la transacción actual.

Otras transacciones no pueden insertar nuevas filas con valores clave que se encuentren en el rango de claves leídas por cualquier declaración en la transacción actual hasta que se complete la transacción actual.

Por lo tanto, el comportamiento que ve está perfectamente explicado por la documentación del producto:

  • UPDLOCK no bloquea SELECT ni INSERT concurrentes, pero bloquea cualquier UPDATE o DELETE de las filas seleccionadas por T1
  • HOLDLOCK significa SERALIZABLE y por lo tanto permite SELECTS, pero bloquea UPDATE y DELETES de las filas seleccionadas por T1, así como cualquier INSERT en el rango seleccionado por T1 (que es la tabla completa, por lo tanto cualquier inserto).
  • (UPDLOCK, HOLDLOCK): su experimento no muestra qué bloquearía además del caso anterior, es decir, otra transacción con UPDLOCK en T2 :
    SELECT * FROM dbo.Test WITH (UPDLOCK) WHERE ...
  • TABLOCKX sin necesidad de explicaciones

La verdadera pregunta es ¿qué estás tratando de lograr ? Jugar con pistas de bloqueo sin una comprensión absoluta del 110% de la semántica de bloqueo está pidiendo problemas ...

Después de la edición OP:

Me gustaría seleccionar filas de una tabla y evitar que los datos de esa tabla se modifiquen mientras los estoy procesando.

Debe utilizar uno de los niveles de aislamiento de transacciones más altos. La LECTURA REPETIBLE evitará que se modifiquen los datos que lee. SERIALIZABLE evitará que se modifiquen los datos que lee y que se inserten nuevos datos. Usar niveles de aislamiento de transacciones es el enfoque correcto, en lugar de usar sugerencias de consulta. Kendra Little tiene un bonito póster que explica los niveles de aislamiento .

Remus Rusanu
fuente
+1 y gracias por la respuesta detallada. Actualizaré mi pregunta para agregar el detalle de cuál es mi objetivo.
Jeff Ogata
1
@Remus Rusanu, ¿podría explicar por qué el enfoque correcto es usar niveles de aislamiento en lugar de usar sugerencias de consulta? Tengo un procedimiento en el que solo necesito bloquear dos tablas para que no se modifiquen y estoy usando TABLOCK, HOLDLOCK, ¿debería realmente cambiar al nivel de aislamiento y bloquear todas las tablas en mi transacción?
Steve
Me gustaría una explicación para TABLOCKX :)
niico
Nota: El enlace para la entrada del blog de Kendra Little devuelve un 404. No puedo encontrar ninguna entrada con fecha del 2 de febrero de 2011, como sugiere el enlace.
Tocino Bits
22

UPDLOCK se usa cuando desea bloquear una fila o filas durante una instrucción de selección para una declaración de actualización futura. La futura actualización podría ser la siguiente declaración de la transacción.

Otras sesiones aún pueden ver los datos. Simplemente no pueden obtener bloqueos que sean incompatibles con UPDLOCK y / o HOLDLOCK.

Utiliza UPDLOCK cuando desea evitar que otras sesiones cambien las filas que ha bloqueado. Restringe su capacidad para actualizar o eliminar filas bloqueadas.

Utiliza HOLDLOCK cuando desea evitar que otras sesiones cambien los datos que está viendo. Restringe su capacidad para insertar, actualizar o eliminar las filas que ha bloqueado. Esto le permite ejecutar la consulta nuevamente y ver los mismos resultados.

Scott Bruns
fuente
1
Gracias, pero no creo que haya respondido realmente a mi pregunta: ¿fueron incorrectas las respuestas a esas preguntas al indicar que el (UPDLOCK,HOLDLOCK)bloque lee, y hay una razón para usar en (UPDLOCK,HOLDLOCK)lugar de solo (HOLDLOCK)?
Jeff Ogata
Mi segunda afirmación responde a su pregunta, están equivocadas. Otras sesiones aún pueden leer los datos.
Scott Bruns
Updlock, Holdlock no es lo mismo que holdlock. Updlock, holdlock bloquea las filas para actualizar y serializa su transacción. Holdlock por sí solo solo serializa su transacción. No bloquea las filas seleccionadas para un mayor acceso.
Scott Bruns
"UPDLOCK se usa cuando desea bloquear una fila o filas durante una instrucción de selección para una declaración de actualización futura". Me encanta esto, ya que XLOCK puede no estar funcionando en algún momento
Yiping