TABLOCK vs TABLOCKX

cuál es la diferencia entre TABLOCK y TABLOCKX http://msdn.microsoft.com/en-us/library/ms187373.aspx indica que TABLOCK es un locking compartido mientras que TABLOCKX es un locking exclusivo. ¿Es posible que el primero sea solo un locking de índice? ¿Y cuál es el concepto de compartir un candado?

Gran diferencia, TABLOCK intentará obtener lockings “compartidos” y TABLOCKX exclusivos TABLOCKX .

Si está en una transacción y agarra un candado exclusivo en una mesa, por ejemplo:

SELECT 1 FROM TABLE WITH (TABLOCKX)

Ningún otro proceso podrá tomar lockings en la tabla, lo que significa que todas las consultas que intenten comunicarse con la tabla se bloquearán hasta que la transacción se comprometa.

TABLOCK solo captura un locking compartido, los lockings compartidos se liberan después de que se ejecuta una instrucción si el aislamiento de la transacción es READ COMMITTED (predeterminado). Si su nivel de aislamiento es más alto , por ejemplo: SERIALIZABLE , los lockings compartidos se mantienen hasta el final de una transacción.


Los lockings compartidos son, hmmm, compartidos. Las transacciones de significado 2 pueden leer datos de la tabla al mismo tiempo si ambos tienen un locking S o IS en la tabla (a través de TABLOCK ). Sin embargo, si la transaction A contiene un locking compartido en una tabla, la transaction B no podrá obtener un locking exclusivo hasta que se liberen todos los lockings compartidos. Lea acerca de qué lockings son compatibles con los que en msdn .


Ambas sugerencias hacen que el db evite tomar lockings más granulares (como lockings de nivel de página o fila). En principio, los lockings más granulares le permiten una mejor concurrencia. Entonces, por ejemplo, una transacción podría estar actualizando la fila 100 en su tabla y otra fila 1000, al mismo tiempo desde dos transacciones (se complica con lockings de página, pero salteemos eso).

En general, lockings granulares es lo que desea, pero a veces es posible que desee reducir la concurrencia de db para boost el rendimiento de una operación en particular y eliminar la posibilidad de interlockings.

En general, no usaría TABLOCK o TABLOCKX menos que lo necesitara por algún caso extremo.

Un antiguo artículo sobre mssqlcity intenta explicar los tipos de lockings:

Los lockings compartidos se usan para operaciones que no cambian ni actualizan datos, como una instrucción SELECT.

Los lockings de actualización se usan cuando SQL Server intenta modificar una página y luego promueve el locking de la página de actualización a un locking de página exclusivo antes de realizar los cambios.

Los lockings exclusivos se utilizan para las operaciones de modificación de datos, como ACTUALIZAR, INSERTAR o ELIMINAR.

Lo que no se discute es intención (que básicamente es un modificador para estos tipos de cerradura). Los lockings con intención (compartida / exclusiva) son lockings mantenidos en un nivel más alto que el locking real. Entonces, por ejemplo, si su transacción tiene un locking X en una fila, también tendrá un locking IX en el nivel de la tabla (lo que impide que otras transacciones intenten obtener un locking incompatible en un nivel superior de la tabla (por ejemplo, un esquema locking de modificación) hasta que su transacción finalice o deshaga).


El concepto de “compartir” un candado es bastante sencillo: las transacciones múltiples pueden tener un candado compartido para el mismo recurso, mientras que solo una transacción puede tener un candado exclusivo y un candado exclusivo impide que cualquier transacción obtenga o mantenga un candado compartido.

Este es más un ejemplo donde TABLOCK no funcionó para mí y lo hizo TABLOCKX.

Tengo 2 sesiones, ambas utilizan el nivel de aislamiento predeterminado (LECTURA COMPROMETIDA):

La sesión 1 es una transacción explícita que copiará los datos de un servidor vinculado a un conjunto de tablas en una base de datos, y tarda unos segundos en ejecutarse. [Ejemplo, elimina preguntas] La sesión 2 es una instrucción de inserción, que simplemente inserta filas en una tabla en la que la Sesión 1 no realiza cambios. [Ejemplo, inserta respuestas].

(En la práctica, hay múltiples sesiones insertando múltiples registros en la tabla, simultáneamente, mientras que la Sesión 1 está ejecutando su transacción).

La sesión 1 tiene que consultar la tabla en la que se inserta la sesión 2 porque no puede eliminar los registros que dependen de las entradas que se agregaron en la sesión 2. [Ejemplo: eliminar preguntas que no han sido respondidas].

Por lo tanto, mientras la Sesión 1 se está ejecutando y la Sesión 2 intenta insertarse, la Sesión 2 pierde en un punto muerto cada vez.

Por lo tanto, una instrucción delete en la sesión 1 podría verse más o menos así: DELETE tblA FROM tblQ LEFT JOIN tblX on … LEFT JOIN tblA a ON tblQ.Qid = tblA.Qid WHERE … a.QId ES NULL y …

El interlocking parece ser causado por la disputa entre consultar tblA, mientras que la sesión 2, [3, 4, 5, …, n] intentar insertar en tblA.

En mi caso, podría cambiar el nivel de aislamiento de la transacción de la Sesión 1 para que sea SERIALIZABLE. Cuando hice esto: el administrador de transacciones ha deshabilitado su soporte para transacciones remotas / de red.

Entonces, podría seguir las instrucciones en la respuesta aceptada aquí para evitarlo: el administrador de transacciones ha deshabilitado su soporte para transacciones remotas / de red

Pero a) No me sentía cómodo con el cambio del nivel de aislamiento a SERIALIZABLE en primer lugar, supuestamente degrada el rendimiento y puede haber otras consecuencias que no he considerado, b) no entendí por qué al hacer esto repentinamente la transacción tuvo un problema al trabajar con servidores vinculados, yc) no sé qué posibles agujeros podría estar abriendo al permitir el acceso a la red.

Parecía haber solo 6 consultas dentro de una transacción muy grande que están causando el problema.

Entonces, leí sobre TABLOCK y TabLOCKX.

No era muy claro sobre las diferencias, y no sabía si alguno de ellos funcionaría. Pero parecía que sí. Primero probé TABLOCK y no pareció hacer ninguna diferencia. Las sesiones de la competencia generaron los mismos puntos muertos. Luego probé TABLOCKX, y no más puntos muertos.

Entonces, en seis lugares, todo lo que tenía que hacer era agregar un WITH (TABLOCKX).

Por lo tanto, una instrucción delete en la sesión 1 podría verse más o menos así: DELETE tblA FROM tblQ q LEFT JOIN tblX x on … LEFT JOIN tblA a WITH (TABLOCKX) ON tblQ.Qid = tblA.QUID WHERE … a.QId IS NULL y …