Compartir vía


Guía de interbloqueos

Se aplica a: SQL Server Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW)

En este artículo se describen los interbloqueos en el motor de base de datos de SQL Server en profundidad. Los interbloqueos se producen por bloqueos simultáneos en competencia en la base de datos, a menudo en transacciones de varios pasos. Para más información sobre el bloqueo de transacciones, consulte Guía de control de versiones de fila y bloqueo de transacciones.

Para obtener más información específica para identificar y prevenir los interbloqueos de Azure SQL Database, consulte Análisis y prevención de interbloqueos en Azure SQL Database.

Descripción de los interbloqueos

Un interbloqueo se produce cuando dos o más tareas se bloquean entre sí permanentemente teniendo cada tarea un bloqueo en un recurso que las otras tareas intentan bloquear. Por ejemplo:

  • La transacción A adquiere un bloqueo compartido de la fila 1.

  • La transacción B adquiere un bloqueo compartido de la fila 2.

  • Ahora la transacción A solicita un bloqueo exclusivo de la fila 2 y se bloquea hasta que la transacción B finalice y libere el bloqueo compartido que tiene de la fila 2.

  • Ahora la transacción B solicita un bloqueo exclusivo de la fila 1 y se bloquea hasta que la transacción A finalice y libere el bloqueo compartido que tiene de la fila 1.

La transacción A no puede completarse hasta que se complete la transacción B, pero la transacción B está bloqueada por la transacción A. Esta condición también se llama dependencia cíclica: la transacción A tiene una dependencia de la transacción B y la transacción B cierra el círculo teniendo una dependencia de la transacción A.

Ambas transacciones con un interbloqueo esperarán para siempre, a no ser que un proceso externo rompa el interbloqueo. La supervisión de interbloqueos del motor de base de datos de SQL Server comprueba periódicamente si hay tareas con un interbloqueo. Si el monitor detecta una dependencia cíclica, elige una de las tareas como el sujeto y finaliza su transacción con un error. Esto permite a la otra tarea completar su transacción. La aplicación con la transacción que terminó con un error puede reintentar la transacción, que suele completarse después de que la otra transacción interbloqueada haya finalizado.

A menudo se confunden los interbloqueos con los bloqueos normales. Cuando una transacción solicita un bloqueo en un recurso bloqueado por otra transacción, la transacción solicitante espera hasta que se libere el bloqueo. De manera predeterminada, las transacciones de SQL Server no tienen tiempo de espera, a menos que se establezca LOCK_TIMEOUT. La transacción solicitante está bloqueada, no interbloqueada, porque la transacción solicitante no ha hecho nada para bloquear la transacción a la que pertenece el bloqueo. Finalmente, la transacción a la que pertenece el bloqueo se completará y liberará el bloqueo, y a la transacción solicitante se le concederá el bloqueo y continuará. Los interbloqueos se resuelven casi inmediatamente, mientras que el bloqueo puede, en teoría, persistir indefinidamente. A veces, los interbloqueos se denominan "abrazo mortal".

Un interbloqueo se puede producir en cualquier sistema con varios subprocesos, no solo en un sistema de administración de bases de datos relacionales, y puede producirse para recursos distintos a los bloqueos en objetos de base de datos. Por ejemplo, un subproceso en un sistema operativo con varios subprocesos puede adquirir uno o más recursos, como bloqueos de memoria. Si el recurso que se va a adquirir pertenece actualmente a otro subproceso, es posible que el primer subproceso deba esperar a que el otro libere el recurso de destino. En consecuencia, se dice que el subproceso que está en espera depende del subproceso que posee ese recurso concreto. En una instancia del motor de base de datos de SQL Server, las sesiones pueden interbloquearse cuando adquieren recursos ajenos a la base de datos, como memoria o subprocesos.

Diagrama que muestra un bloqueo de transacción.

En la ilustración, la transacción T1 tiene una dependencia de la transacción T2 para el recurso de bloqueo de la tabla Part. Del mismo modo, la transacción T2 tiene una dependencia de la transacción T1 para el recurso de bloqueo de la tabla Supplier. Puesto que estas dependencias forman un ciclo, hay un interbloqueo entre las transacciones T1 y T2.

Los interbloqueos también se pueden producir cuando se crean particiones en una tabla y el valor LOCK_ESCALATION de ALTER TABLE se establece en AUTO. Cuando LOCK_ESCALATION se establece en AUTO, la simultaneidad aumenta permitiendo al motor de base de datos de SQL Server bloquear las particiones de la tabla en el nivel HoBT en lugar de en el nivel de tabla. Sin embargo, cuando transacciones independientes mantienen bloqueos de partición en una tabla y desean un bloqueo en algún punto de la partición de otras transacciones, se produce un interbloqueo. Este tipo de interbloqueo se puede evitar estableciendo LOCK_ESCALATION en TABLE. Sin embargo, esta configuración reduce la simultaneidad al forzar las actualizaciones de gran tamaño a una partición para esperar un bloqueo de tabla.

Detección y finalización de interbloqueos

Un interbloqueo se produce cuando dos o más tareas se bloquean entre sí permanentemente teniendo cada tarea un bloqueo en un recurso que las otras tareas intentan bloquear. En el siguiente gráfico se presenta una vista de alto nivel de un estado de interbloqueo donde:

  • La tarea T1 tiene un bloqueo en el recurso R1 (indicado por la flecha de R1 a T1) y ha solicitado un bloqueo en el recurso R2 (indicado por la flecha de T1 a R2).

  • La tarea T2 tiene un bloqueo en el recurso R2 (indicado por la flecha de R2 a T2) y ha solicitado un bloqueo en el recurso R1 (indicado por la flecha de T2 a R1).

  • Dado que ninguna tarea puede continuar hasta que un recurso esté disponible y ningún recurso puede liberarse hasta que continúe una tarea, existe un estado de interbloqueo.

    Diagrama en el que se muestran tareas en un estado de bloqueo.

El motor de base de datos de SQL Server detecta automáticamente ciclos de interbloqueo dentro de SQL Server. El motor de base de datos de SQL Server elige una de las sesiones como sujeto del interbloqueo y la transacción actual finaliza con un error para romper el interbloqueo.

Recursos que pueden causar interbloqueos

Cada sesión de usuario puede tener una o más tareas en ejecución y cada tarea puede adquirir o esperar para adquirir recursos. Los siguientes tipos de recursos pueden causar bloqueos que podrían dar como resultado un interbloqueo.

  • Bloqueos. Esperar para adquirir bloqueos en recursos, como objetos, páginas, filas, metadatos y aplicaciones, puede causar un interbloqueo. Por ejemplo, la transacción T1 tiene un bloqueo compartido (S) en la fila f1 y está esperando para obtener un bloqueo exclusivo (X) en f2. La transacción T2 tiene un bloqueo compartido (S) en f2 y está esperando para obtener un bloqueo exclusivo (X) en la fila f1. Esta situación tiene como resultado un ciclo de bloqueo en el que T1 y T2 esperan que la otra transacción libere los recursos bloqueados.

  • Subprocesos de trabajo. Una tarea en cola que espera un subproceso de trabajo disponible puede causar un interbloqueo. Si la tarea en cola es propietaria de recursos que están bloqueando todos los subprocesos de trabajo, se generará un interbloqueo. Por ejemplo, la sesión S1 inicia una transacción y adquiere un bloqueo compartido (S) en la fila f1 y, a continuación, se suspende. Las sesiones activas que se ejecutan en todos los subprocesos de trabajo disponibles intentan adquirir bloqueos exclusivos (X) en la fila f1. Dado que la sesión S1 no puede adquirir un subproceso de trabajo, no puede confirmar la transacción y liberar el bloqueo de la fila f1. Esta situación tiene como resultado un interbloqueo.

  • Memory. Cuando hay solicitudes simultáneas esperando concesiones de memoria que no se pueden satisfacer con la memoria disponible, puede producirse un interbloqueo. Por ejemplo, dos consultas simultáneas, C1 y C2, se ejecutan como funciones definidas por el usuario que adquieren 10 MB y 20 MB de memoria, respectivamente. Si cada consulta necesita 30 MB y el total de memoria disponible es 20 MB, Q1 y Q2 tienen que esperar a que la otra consulta libere memoria, y esta situación tiene como resultado un interbloqueo.

  • Recursos relacionados con la ejecución de consultas en paralelo. Los subprocesos de coordinador, productor o consumidor asociados a un puerto de intercambio se pueden bloquear entre sí y provocar un interbloqueo si incluyen al menos otro proceso que no forma parte de la consulta en paralelo. Además, cuando se inicia la ejecución de una consulta en paralelo, SQL Server determina el grado de paralelismo, o el número de subprocesos de trabajo, en función de la carga de trabajo actual. Si la carga de trabajo del sistema cambia de forma inesperada, por ejemplo, si se empiezan a ejecutar nuevas consultas en el servidor o el sistema se queda sin subprocesos de trabajo, se puede producir un interbloqueo.

  • Conjuntos de resultados activos múltiples (MARS). Estos recursos se utilizan para controlar la intercalación de varias solicitudes activas en MARS. Para obtener más información, vea Utilizar conjuntos de resultados activos múltiples (MARS) en SQL Server Native Client.

    • Recurso de usuario. Cuando un subproceso espera un recurso que potencialmente está controlado por una aplicación de usuario, se considera que el recurso es externo o de usuario y se trata como un bloqueo.

    • Exclusión mutua de sesión. Las tareas que se ejecutan en una sesión se intercalan, lo que significa que solo puede ejecutarse una tarea en la sesión en un momento dado. Antes de que se pueda ejecutar la tarea, debe tener acceso exclusivo a la exclusión mutua de sesión.

    • Exclusión mutua de transacción. Todas las tareas que se ejecutan en una transacción se intercalan, lo que significa que solo puede ejecutarse una tarea en la transacción en un momento dado. Antes de que se pueda ejecutar la tarea, debe tener acceso exclusivo a la exclusión mutua de transacción.

      Para que una tarea se ejecute en MARS, debe adquirir la exclusión mutua de sesión. Si la tarea se ejecuta en una transacción, debe adquirir la exclusión mutua de transacción. Esto garantiza que solo una tarea esté activa en un momento dado en una sesión determinada y en una transacción concreta. Una vez adquiridas las exclusiones mutuas necesarias, se puede ejecutar la tarea. Cuando finaliza la tarea, o se produce en medio de la solicitud, primero liberará la exclusión mutua de transacción seguida de la exclusión mutua de sesión en el orden inverso a la adquisición. Sin embargo, pueden producirse interbloqueos con estos recursos. En el pseudocódigo siguiente hay dos tareas, la solicitud de usuario U1 y la solicitud de usuario U2, que se ejecutan en la misma sesión.

      U1:    Rs1=Command1.Execute("insert sometable EXEC usp_someproc");
      U2:    Rs2=Command2.Execute("select colA from sometable");
      

      El procedimiento almacenado que se ejecuta a partir de la solicitud de usuario U1 ha adquirido la exclusión mutua de sesión. Si el procedimiento almacenado tarda mucho tiempo en ejecutarse, el motor de base de datos de SQL Server considerará que el procedimiento almacenado está esperando la intervención del usuario. La solicitud de usuario U2 está esperando la exclusión mutua de sesión mientras que el usuario está esperando el conjunto de resultados de U2, y U1 está esperando un recurso de usuario. Éste es un estado de interbloqueo que se ilustra de forma lógica como:

      Diagrama del flujo lógico de un procedimiento almacenado en MARS.

Detección de interbloqueos

Todos los recursos enumerados en la sección Recursos que pueden interbloquear participan en el esquema de detección de interbloqueos del motor de base de datos de SQL Server. La detección de interbloqueos la realiza un subproceso de supervisión de bloqueos que periódicamente inicia una búsqueda por todas las tareas de una instancia del motor de base de datos de SQL Server. En los siguientes puntos se describe el proceso de búsqueda:

  • El intervalo predeterminado es de 5 segundos.

  • Si el subproceso de supervisión de bloqueos encuentra interbloqueos, el intervalo de detección de interbloqueos pasa de 5 segundos a hasta solo 100 milisegundos, en función de la frecuencia de los interbloqueos.

  • Si el subproceso de supervisión de bloqueos deja de encontrar interbloqueos, el motor de base de datos de SQL Server aumentará los intervalos entre las búsquedas a 5 segundos.

  • Si se detecta un interbloqueo, se considera que los siguientes subprocesos que deben esperar un bloqueo entran en el ciclo de interbloqueo. Las primeras y pocas esperas de bloqueo después de que se haya detectado un interbloqueo desencadenan inmediatamente una búsqueda de interbloqueos, en vez de esperar al siguiente intervalo de detección de interbloqueos. Por ejemplo, si el intervalo actual es de 5 segundos y se acaba de detectar un interbloqueo, la siguiente espera de bloqueo activa inmediatamente el detector de interbloqueos. Si esta espera de bloqueo forma parte de un interbloqueo, se detecta enseguida en lugar de durante la siguiente búsqueda de interbloqueos.

El motor de base de datos de SQL Server solo suele realizar detecciones de interbloqueos periódicas. Dado que el número de interbloqueos que se encuentran en el sistema suele ser pequeño, si se detectan periódicamente, el sistema no se ve sobrecargado por este tipo de detecciones.

Cuando el monitor de bloqueos inicia una búsqueda de interbloqueos para un subproceso determinado, identifica el recurso que está esperando. Después, el monitor de bloqueos encuentra a los propietarios de ese recurso y continúa recursivamente la búsqueda de interbloqueos para esos subprocesos hasta que encuentra un ciclo. Un ciclo que se identifica de esta manera forma un interbloqueo.

Una vez detectado un interbloqueo, el motor de base de datos de SQL Server finaliza un interbloqueo eligiendo uno de los subprocesos como sujeto del interbloqueo. El motor de base de datos de SQL Server finaliza el lote actual que se está ejecutando para el subproceso, revierte la transacción del sujeto del interbloqueo y devuelve un error 1205 a la aplicación. Revertir la transacción para el sujeto del interbloqueo libera todos los bloqueos que tiene la transacción. Esto permite que las transacciones de otros subprocesos se desbloqueen y continúen. El error 1205 del sujeto del interbloqueo registra información sobre los subprocesos y recursos implicados en un interbloqueo en el registro de errores.

De manera predeterminada, el motor de base de datos de SQL Server elige como sujeto del interbloqueo la sesión que ejecuta la transacción cuya reversión resulta menos costosa. Como alternativa, un usuario puede especificar la prioridad de las sesiones en una situación de interbloqueo mediante la instrucción SET DEADLOCK_PRIORITY. DEADLOCK_PRIORITY puede establecerse en LOW, NORMAL o HIGH; también puede establecerse como un valor entero en el intervalo de -10 a 10. El valor predeterminado de la prioridad de interbloqueo es NORMAL. Si dos sesiones tienen distintas prioridades de interbloqueo, la sesión con la prioridad menor se elige como el sujeto del interbloqueo. Si ambas sesiones tienen la misma prioridad de interbloqueo, se elige la sesión con la transacción cuya reversión resulta menos costosa. Si las sesiones implicadas en el ciclo de interbloqueo tienen la misma prioridad de interbloqueo y el mismo costo, se elige un sujeto de forma aleatoria.

Cuando se trabaja con el idioma común en tiempo de ejecución (CLR), el monitor de interbloqueos detecta automáticamente el interbloqueo de los recursos de sincronización (monitores, bloqueo de lectura y escritura, y combinación de subprocesos) a los que se ha tenido acceso dentro de los procedimientos administrados. Si embargo, el interbloqueo se resuelve iniciando una excepción en el procedimiento que se seleccionó como sujeto del interbloqueo. Es importante comprender que la excepción no libera automáticamente los recursos que posee actualmente el sujeto; los recursos se tienen que liberar de forma explícita. De forma coherente con el comportamiento de la excepción, la excepción utilizada para identificar un sujeto del interbloqueo se puede interceptar y descartar.

Herramientas de información de interbloqueos

Para ver la información de interbloqueos, el motor de base de datos de SQL Server proporciona herramientas de supervisión en la forma de la sesión system_health de XEvent, dos marcas de seguimiento y el evento de gráfico de interbloqueo en SQL Profiler.

Nota:

Esta sección contiene información sobre eventos extendidos, marcas de seguimiento y seguimientos, pero el evento extendido Deadlock es el método recomendado para capturar información de interbloqueo.

Evento extendido de interbloqueo

A partir de SQL Server 2012 (11.x), se debe usar el evento extendido xml_deadlock_report (XEvent) en lugar de la clase de eventos de gráfico de interbloqueo en Seguimiento de SQL o SQL Profiler.

Cuando se producen interbloqueos, la sesión system_health ya captura todos los XEvents xml_deadlock_report que contienen el gráfico de interbloqueo. Dado que la sesión system_health está habilitada de forma predeterminada, no es necesario configurar una sesión de XEvent aparte para capturar la información de interbloqueos. No se requiere ninguna acción adicional para capturar información de interbloqueo con el XEvent xml_deadlock_report.

El grafo de interbloqueo que se capturaba normalmente consta de tres nodos distintos:

  • victim-list. Identificador de proceso del elemento afectado por el interbloqueo.
  • process-list. Información sobre todos los procesos implicados en el interbloqueo.
  • resource-list. Información sobre todos los recursos implicados en el interbloqueo.

Al abrir el archivo de la sesión system_health o el búfer en anillo, si se registra el XEvent xml_deadlock_report, Management Studio presenta una representación gráfica de las tareas y recursos que participan en un interbloqueo, tal como se muestra en el ejemplo siguiente:

Captura de pantalla de SSMS de un diagrama visual del grafo de bloqueo de XEvent.

La consulta siguiente puede ver todos los eventos de interbloqueo capturados por la sesión system_health del búfer en anillo:

SELECT xdr.value('@timestamp', 'datetime') AS [Date],
       xdr.query('.') AS [Event_Data]
FROM (SELECT CAST ([target_data] AS XML) AS Target_Data
      FROM sys.dm_xe_session_targets AS xt
           INNER JOIN sys.dm_xe_sessions AS xs
               ON xs.address = xt.event_session_address
      WHERE xs.name = N'system_health'
            AND xt.target_name = N'ring_buffer') AS XML_Data
      CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr)
ORDER BY [Date] DESC;

Este es el conjunto de resultados.

Captura de pantalla de SSMS del resultado de la consulta system_health XEvent.

En el ejemplo siguiente se muestra el resultado, después de seleccionar el primer vínculo en Event_Data en la primera fila del resultado:

<event name="xml_deadlock_report" package="sqlserver" timestamp="2022-02-18T08:26:24.698Z">
  <data name="xml_report">
    <type name="xml" package="package0" />
    <value>
      <deadlock>
        <victim-list>
          <victimProcess id="process27b9b0b9848" />
        </victim-list>
        <process-list>
          <process id="process27b9b0b9848" taskpriority="0" logused="0" waitresource="KEY: 5:72057594214350848 (1a39e6095155)" waittime="1631" ownerId="11088595" transactionname="SELECT" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27b9f79fac0" lockMode="S" schedulerid="9" kpid="15336" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2022-02-18T00:26:22.893" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="7908" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088595" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2022.dbo.p1" line="3" stmtstart="78" stmtend="180" sqlhandle="0x0300050020766505ca3e07008ba8000001000000000000000000000000000000000000000000000000000000">
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x020000006263ec01ebb919c335024a072a2699958d3fcce60000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
    EXEC p1 4
END
   </inputbuf>
          </process>
          <process id="process27b9ee33c28" taskpriority="0" logused="252" waitresource="KEY: 5:72057594214416384 (e5b3d7e750dd)" waittime="1631" ownerId="11088593" transactionname="UPDATE" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27ba15a4490" lockMode="X" schedulerid="6" kpid="5584" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-02-18T00:26:22.890" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="15316" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088593" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2022.dbo.p2" line="3" stmtstart="76" stmtend="150" sqlhandle="0x03000500599a5906ce3e07008ba8000001000000000000000000000000000000000000000000000000000000">
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x02000000008fe521e5fb1099410048c5743ff7da04b2047b0000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
    EXEC p2 4
END
   </inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057594214350848" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="cidx" id="lock27b9dd26a00" mode="X" associatedObjectId="72057594214350848">
            <owner-list>
              <owner id="process27b9ee33c28" mode="X" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9b0b9848" mode="S" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594214416384" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="idx1" id="lock27afa392600" mode="S" associatedObjectId="72057594214416384">
            <owner-list>
              <owner id="process27b9b0b9848" mode="S" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9ee33c28" mode="X" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </value>
  </data>
</event>

Para obtener más información, consulte Usar la sesión system_health

Marcas de seguimiento 1204 y 1222

Cuando se produce el interbloqueo, los marcadores de seguimiento 1204 y 1222 devuelven la información que se ha capturado en el registro de errores de SQL Server. El marcador de seguimiento 1204 informa sobre el interbloqueo con un formato que especifica cada nodo implicado en el mismo. El marcador de seguimiento 1222 aplica formato a la información de interbloqueo, primero por procesos y luego por recursos. Es posible habilitar ambas marcas de seguimiento para obtener dos representaciones del mismo evento de interbloqueo.

Importante

Evite utilizar la marca de seguimiento 1204 y 1222 en sistemas con un uso intensivo de cargas de trabajo que causan interbloqueos. Es posible que el uso de estas marcas de seguimiento genere problemas de rendimiento. En su lugar, use el evento extendido de interbloqueo para capturar la información necesaria.

Además de definir las propiedades de las marcas de seguimiento 1204 y 1222, en la siguiente tabla se muestran las similitudes y las diferencias.

Propiedad Marcas de seguimiento 1204 y 1222 Solo marca de seguimiento 1204 Solo marca de seguimiento 1222
Formato de salida Los resultados se capturan en el registro de errores de SQL Server. Se centra en los nodos implicados en el interbloqueo. Cada nodo tiene una sección dedicada y la última sección describe al sujeto del interbloqueo. Devuelve información en un formato XML que no se ajusta a un esquema de definición de esquemas XML (XSD). El formato tiene tres secciones principales. La primera sección declara el sujeto del interbloqueo. La segunda sección describe los procesos implicados en el interbloqueo. La tercera sección describe los recursos que son sinónimos de nodos en la marca de seguimiento 1204.
Atributos de identificación SPID:<x> ECID:<x>. Identifica el subproceso del identificador de proceso del sistema en los casos de procesos paralelos. La entrada SPID:<x> ECID:0, en que <x> se sustituye por el valor del SPID, representa el subproceso principal. La entrada SPID:<x> ECID:<y>, en que <x> se sustituye por el valor del SPID y <y> es mayor que 0, representa los subprocesos secundarios del mismo SPID.

BatchID (sbid para marca de seguimiento 1222). Identifica el lote desde el que la ejecución del código está solicitando o manteniendo un bloqueo. Cuando se deshabilita Multiple Active Result Sets (MARTE), el valor de BatchID es 0. Cuando se habilita MART, el valor para los lotes activos es 1 para n. Si en la sesión no hay lotes activos, BatchID es 0.

Mode Especifica el tipo de bloqueo de un recurso en concreto que un subproceso solicita, concede o espera. Mode puede ser IS (Intención compartida), S (Compartido), U (Actualizar), IX (Intención exclusiva), SIX (Intención compartida exclusiva) y X (Exclusiva).

Line # (line para marca de seguimiento 1222). Indica el número de línea en el lote actual de instrucciones que se estaba ejecutando cuando se produjo el interbloqueo.

Input Buf (inputbuf para marca de seguimiento 1222). Indica todas las instrucciones del lote actual.
Node Representa el numero de entrada en la cadena de interbloqueo.

Lists El propietario del bloqueo puede formar parte de estas listas:

Grant List Enumera los propietarios actuales del recurso.

Convert List Enumera los propietarios actuales que están intentando convertir sus bloqueos a un nivel más alto.

Wait List Enumera las solicitudes actuales del nuevo bloqueo para el recurso.

Statement Type Describe el tipo de instrucción DML (SELECT, INSERT, UPDATE o DELETE) en que los subprocesos tienen permisos.

Victim Resource Owner Especifica el subproceso participante que SQL Server elige como sujeto para interrumpir el ciclo de interbloqueo. El subproceso elegido y todos los subprocesos secundarios finalizan.

Next Branch Representa los dos o más subprocesos secundarios del mismo SPID que están implicados en el ciclo de interbloqueo.
deadlock victim representa la dirección de la memoria física de la tarea (vea sys.dm_os_tasks) que se seleccionó como sujeto del interbloqueo. Puede ser 0 (cero) en caso de un interbloqueo sin resolver. Una tarea que se está revirtiendo no se puede seleccionar como sujeto del interbloqueo.

executionstack Representa el código Transact-SQL que se está ejecutando en el momento en que se produce el interbloqueo.

priority Representa la prioridad de interbloqueo. En ciertos casos, el motor de base de datos de SQL Server puede optar por modificar la prioridad de interbloqueo durante una breve duración para conseguir una mejor simultaneidad.

logused Espacio de registro utilizado por la tarea.

owner id El Id. de la transacción que tiene el control de la solicitud.

status Estado de la tarea. Es uno de los siguientes valores:

- pending Esperando un subproceso de trabajo.

- runnable Preparado para ejecutarse pero esperando un cuanto.

- running Ejecutándose actualmente en el programador.

- suspended La ejecución se ha suspendido.

- done La tarea se ha completado.

- spinloop Esperando que un bloqueo por bucle esté disponible.

waitresource El recurso que la tarea necesita.

waittime Tiempo en milisegundos de espera del recurso.

schedulerid Programador asociado a esta tarea. Consulte sys.dm_os_schedulers.

hostname El nombre de la estación de trabajo.

isolationlevel El nivel de aislamiento de transacción actual.

Xactid El Id. de la transacción que tiene el control de la solicitud.

currentdb El Id. de la base de datos.

lastbatchstarted La última vez que un proceso de cliente inició la ejecución de lotes.

lastbatchcompleted La última vez que un proceso de cliente completó la ejecución de lotes.

clientoption1 y clientoption2 Opciones establecidas en esta conexión de cliente. Se trata de una máscara de bits que incluye información acerca de las opciones controladas normalmente por instrucciones SET, como SET NOCOUNT y SET XACTABORT.

associatedObjectId Representa el identificador del montículo o árbol B (HoBt).
Atributos del recurso RID identifica la única fila de una tabla en la que se mantiene o se solicita un bloqueo. RID se representa como RID: db_id:file_id:page_no:row_no. Por ejemplo, RID: 6:1:20789:0.

OBJECT identifica la tabla en la que se mantiene o se solicita un bloqueo. OBJECT se representa como OBJECT: db_id:object_id. Por ejemplo, TAB: 6:2009058193.

KEY Identifica el intervalo de clave de un índice en el que se mantiene o se solicita un bloqueo. KEY se representa como KEY: db_id:hobt_id (valor de hash de clave de índice). Por ejemplo, KEY: 6:72057594057457664 (350007a4d329).

PAG Identifica el recurso de página en el que se mantiene o se solicita un bloqueo. PAG se representa como PAG: db_id:file_id:page_no. Por ejemplo, PAG: 6:1:20789.

EXT Identifica la estructura de extensión. EXT se representa como EXT: db_id:file_id:extent_no. Por ejemplo, EXT: 6:1:9.

DB Identifica el bloqueo de la base de datos. DB se representa de una de las siguientes maneras:

DB: db_id

DB: db_id[BULK-OP-DB], que identifica el bloqueo de base de datos realizado por la copia de seguridad de la base de datos.

DB: db_id[BULK-OP-LOG], que identifica el bloqueo realizado por el registro de copia de seguridad de esa base de datos en concreto.

APP Identifica el bloqueo realizado por un recurso de la aplicación. APP se representa como APP: lock_resource. Por ejemplo, APP: Formf370f478.

METADATA Representa los recursos de metadatos implicados en un interbloqueo. Debido a que METADATA tiene muchos recursos secundarios, el valor devuelto depende del recurso secundario que se haya interbloqueado. Por ejemplo, METADATA.USER_TYPE devuelve user_type_id = *integer_value*. Para obtener más información acerca de los recursos y recursos secundarios METADATA, vea sys.dm_tran_locks.

HOBT Representa el montículo o árbol B implicado en un interbloqueo.
Nada exclusivo de esta marca de seguimiento. Nada exclusivo de esta marca de seguimiento.

Ejemplo de marca de seguimiento 1204

En el siguiente ejemplo se muestra el resultado que se obtiene cuando se activa una marca de seguimiento 1204. En este caso, la tabla de Node 1 es un montón sin índices, y la tabla de Node 2 es un montón con un índice no clúster. La clave de índice de Node 2 se está actualizando cuando se produce el interbloqueo.

Deadlock encountered .... Printing deadlock information
Wait-for graph

Node:1

RID: 6:1:20789:0               CleanCnt:3 Mode:X Flags: 0x2
 Grant List 0:
   Owner:0x0315D6A0 Mode: X
     Flg:0x0 Ref:0 Life:02000000 SPID:55 ECID:0 XactLockInfo: 0x04D9E27C
   SPID: 55 ECID: 0 Statement Type: UPDATE Line #: 6
   Input Buf: Language Event:
BEGIN TRANSACTION
   EXEC usp_p2
 Requested By:
   ResType:LockOwner Stype:'OR'Xdes:0x03A3DAD0
     Mode: U SPID:54 BatchID:0 ECID:0 TaskProxy:(0x04976374) Value:0x315d200 Cost:(0/868)

Node:2

KEY: 6:72057594057457664 (350007a4d329) CleanCnt:2 Mode:X Flags: 0x0
 Grant List 0:
   Owner:0x0315D140 Mode: X
     Flg:0x0 Ref:0 Life:02000000 SPID:54 ECID:0 XactLockInfo: 0x03A3DAF4
   SPID: 54 ECID: 0 Statement Type: UPDATE Line #: 6
   Input Buf: Language Event:
     BEGIN TRANSACTION
       EXEC usp_p1
 Requested By:
   ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)

Victim Resource Owner:
 ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)

Ejemplo de marca de seguimiento 1222

En el siguiente ejemplo se muestra el resultado que se obtiene cuando se activa una marca de seguimiento 1222. En este caso, una tabla es un montón sin índices y la otra tabla es un montón con un índice no clúster. En la segunda tabla, la clave de índice se está actualizando cuando se produce el interbloqueo.

deadlock-list
 deadlock victim=process689978
  process-list
   process id=process6891f8 taskpriority=0 logused=868
   waitresource=RID: 6:1:20789:0 waittime=1359 ownerId=310444
   transactionname=user_transaction
   lasttranstarted=2022-02-05T11:22:42.733 XDES=0x3a3dad0
   lockMode=U schedulerid=1 kpid=1952 status=suspended spid=54
   sbid=0 ecid=0 priority=0 transcount=2
   lastbatchstarted=2022-02-05T11:22:42.733
   lastbatchcompleted=2022-02-05T11:22:42.733
   clientapp=Microsoft SQL Server Management Studio - Query
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
   isolationlevel=read committed (2) xactid=310444 currentdb=6
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
    executionStack
     frame procname=AdventureWorks2022.dbo.usp_p1 line=6 stmtstart=202
     sqlhandle=0x0300060013e6446b027cbb00c69600000100000000000000
     UPDATE T2 SET COL1 = 3 WHERE COL1 = 1;
     frame procname=adhoc line=3 stmtstart=44
     sqlhandle=0x01000600856aa70f503b8104000000000000000000000000
     EXEC usp_p1
    inputbuf
      BEGIN TRANSACTION
       EXEC usp_p1
   process id=process689978 taskpriority=0 logused=380
   waitresource=KEY: 6:72057594057457664 (350007a4d329)
   waittime=5015 ownerId=310462 transactionname=user_transaction
   lasttranstarted=2022-02-05T11:22:44.077 XDES=0x4d9e258 lockMode=U
   schedulerid=1 kpid=3024 status=suspended spid=55 sbid=0 ecid=0
   priority=0 transcount=2 lastbatchstarted=2022-02-05T11:22:44.077
   lastbatchcompleted=2022-02-05T11:22:44.077
   clientapp=Microsoft SQL Server Management Studio - Query
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
   isolationlevel=read committed (2) xactid=310462 currentdb=6
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
    executionStack
     frame procname=AdventureWorks2022.dbo.usp_p2 line=6 stmtstart=200
     sqlhandle=0x030006004c0a396c027cbb00c69600000100000000000000
     UPDATE T1 SET COL1 = 4 WHERE COL1 = 1;
     frame procname=adhoc line=3 stmtstart=44
     sqlhandle=0x01000600d688e709b85f8904000000000000000000000000
     EXEC usp_p2
    inputbuf
      BEGIN TRANSACTION
        EXEC usp_p2
  resource-list
   ridlock fileid=1 pageid=20789 dbid=6 objectname=AdventureWorks2022.dbo.T2
   id=lock3136940 mode=X associatedObjectId=72057594057392128
    owner-list
     owner id=process689978 mode=X
    waiter-list
     waiter id=process6891f8 mode=U requestType=wait
   keylock hobtid=72057594057457664 dbid=6 objectname=AdventureWorks2022.dbo.T1
   indexname=nci_T1_COL1 id=lock3136fc0 mode=X
   associatedObjectId=72057594057457664
    owner-list
     owner id=process6891f8 mode=X
    waiter-list
     waiter id=process689978 mode=U requestType=wait

Evento Deadlock Graph de Profiler

Este es un evento de SQL Profiler que presenta una descripción gráfica de las tareas y los recursos implicados en un interbloqueo. En el siguiente ejemplo se muestra el resultado de SQL Profiler cuando se ha activado el evento del grafo de interbloqueo.

Importante

SQL Profiler crea seguimientos, que estaban en desuso en 2016 y reemplazados por Eventos extendidos. Los eventos extendidos tienen mucho menos sobrecarga de rendimiento y son mucho más configurables que los seguimientos. Considere la posibilidad de usar el evento de interbloqueo de eventos extendidos en lugar de seguimientos.

Captura de pantalla de SSMS del gráfico de bloqueo visual desde un seguimiento de SQL.

Para obtener más información sobre el evento de interbloqueo, consulte Lock:Deadlock Event Class (Clase de evento Lock:Deadlock). Para obtener más información sobre cómo ejecutar el gráfico de interbloqueo de SQL Profiler, vea Guardar gráficos de interbloqueo (SQL Server Profiler).

Hay equivalentes para las clases de eventos de seguimiento de SQL en Eventos extendidos; consulte Ver los eventos extendidos equivalentes a las clases de evento de Seguimiento de SQL. Los eventos extendidos se recomiendan a través de seguimientos de SQL.

Control de interbloqueos

Cuando una instancia del motor de base de datos de SQL Server elige una transacción como elemento afectado por un interbloqueo, finaliza el lote actual, revierte la transacción y devuelve el mensaje de error 1205 a la aplicación.

Your transaction (process ID #52) was deadlocked on {lock | communication buffer | thread} resources with another process and has been chosen as the deadlock victim. Rerun your transaction.

Dado que cualquier aplicación que envía consultas Transact-SQL puede elegirse como sujeto de un interbloqueo, las aplicaciones deben tener un controlador de errores que pueda interceptar el mensaje de error 1205. Si una aplicación no intercepta el error, puede continuar sin ser consciente de que se ha revertido la transacción y de que se pueden producir errores.

La implementación de un controlador de errores que intercepte el mensaje 1205 permite a una aplicación controlar la situación de interbloqueo y realizar una acción apropiada para solucionarla, por ejemplo, volver a enviar automáticamente la consulta implicada en el interbloqueo. Si se vuelve a enviar la consulta de forma automática, no es necesario que el usuario sepa que se ha producido un interbloqueo.

La aplicación debería realizar una pausa breve antes de volver a enviar su consulta. Esto ofrece a la otra transacción implicada en el interbloqueo una oportunidad de completarse y liberar sus bloqueos que formaban parte del ciclo de interbloqueo. Así se minimiza la probabilidad de que el interbloqueo vuelva a ocurrir cuando la consulta que se ha vuelto a enviar solicite sus bloqueos.

Control con TRY...CATCH

Puede usar TRY...CATCH para controlar interbloqueos. El bloqueo CATCH puede detectar el error del elemento afectado por el interbloqueo 1205 y la transacción se puede revertir hasta que los subprocesos se desbloquean.

Para obtener más información, consulte Control de interbloqueos.

Minimización de interbloqueos

A pesar de que los interbloqueos no se pueden evitar totalmente, si se siguen ciertas convenciones de codificación se puede reducir su número. La minimización de los interbloqueos puede aumentar el rendimiento de las transacciones y reducir la sobrecarga del sistema, debido a que:

  • Se revierten menos transacciones, al deshacer todo el trabajo que realiza la transacción.
  • Las aplicaciones vuelven a enviar menos transacciones debido a que se revirtieron cuando se produjo el interbloqueo.

Para ayudar a reducir los interbloqueos:

  • Obtenga acceso a los objetos en el mismo orden.
  • Evite la interacción con los usuarios en las transacciones.
  • Mantenga transacciones cortas y en un proceso por lotes.
  • Utilice un nivel de aislamiento inferior.
  • Utilice un nivel de aislamiento basado en versiones de fila.
    • Establezca la opción de base de datos READ_COMMITTED_SNAPSHOT en ON para habilitar las transacciones de lectura confirmada y que usen las versiones de fila.
    • Utilice el aislamiento de instantánea.
  • Utilice conexiones enlazadas.

Acceso a los objetos en el mismo orden

Si todas las transacciones simultáneas tienen acceso a los objetos en el mismo orden, es menos probable que se produzcan interbloqueos. Por ejemplo, si dos transacciones simultáneas obtienen un bloqueo en la tabla Supplier y después en la tabla Part, una transacción se bloquea en la tabla Supplier hasta que finalice la otra transacción. Una vez confirmada o revertida la primera transacción, continúa la segunda, por lo que no se produce un interbloqueo. La utilización de procedimientos almacenados para todas las modificaciones de datos puede normalizar el orden de acceso a los objetos.

Diagrama de un bloqueo.

Sin interacción con los usuarios en las transacciones

Evite escribir transacciones que incluyan la intervención del usuario, ya que la velocidad de ejecución de los lotes que no requieren esta intervención es mucho mayor que la velocidad con la que el usuario debe responder manualmente a las consultas como, por ejemplo, contestar a la solicitud de un parámetro por parte de una aplicación. Por ejemplo, si una transacción espera una entrada del usuario y éste sale a comer o no vuelve hasta pasado el fin de semana, dicho usuario retrasa la finalización de la transacción. De esta forma, se degrada el rendimiento del sistema, ya que los bloqueos que mantiene la transacción solo se liberan cuando se confirma o se revierte la transacción. Aunque no surja una situación de interbloqueo, las demás transacciones que acceden a los mismos recursos se bloquean mientras esperan a que la transacción finalice.

Conservación de transacciones cortas y en un proceso por lotes

Normalmente, los interbloqueos se producen cuando varias transacciones de larga duración se ejecutan simultáneamente en la misma base de datos. Cuanto más dure la transacción, más tiempo se mantendrán los bloqueos exclusivos o de actualización, con lo cual se bloquean otras actividades y se originan posibles situaciones de interbloqueo.

Al mantener las transacciones en un proceso por lotes, se minimizan los viajes de ida y vuelta en la red durante una transacción y se reducen los posibles retrasos al completar la transacción y liberar los bloqueos.

Para obtener más información sobre los bloqueos de actualización, vea Guía de versiones de fila y bloqueo de transacciones.

Uso de un nivel de aislamiento inferior

Determine si una transacción se puede ejecutar con un nivel de aislamiento inferior. Al implementar la lectura confirmada, se permite a una transacción leer los datos previamente leídos (no modificados) por otra transacción, sin tener que esperar a que la primera transacción finalice. Un nivel inferior de aislamiento, como la lectura confirmada, mantiene los bloqueos compartidos durante menos tiempo que un nivel superior de aislamiento, como el nivel serializable. De esta forma, se reduce la contención de bloqueos.

Uso de un nivel de aislamiento basado en versiones de fila

Si la opción de base de datos READ_COMMITTED_SNAPSHOT se ha establecido en ON, la transacción que se ejecuta con el nivel de aislamiento de lectura confirmada utiliza las versiones de fila en lugar de bloqueos compartidos durante las operaciones de lectura.

Nota:

Algunas aplicaciones dependen del comportamiento de los bloqueos en el aislamiento de lectura confirmada. En estas aplicaciones, es preciso efectuar algunos cambios antes de habilitar esta opción.

El aislamiento de instantánea también utiliza las versiones de fila, que no emplean bloqueos compartidos en las operaciones de lectura. Antes de ejecutar una transacción con aislamiento de instantánea, debe establecerse en ON la opción de base de datos ALLOW_SNAPSHOT_ISOLATION.

Implemente estos niveles de aislamiento para reducir los interbloqueos que se pueden producir entre operaciones de lectura y escritura.

Utilizar conexiones enlazadas

Al utilizar conexiones enlazadas, dos o más conexiones abiertas por la misma aplicación pueden cooperar entre sí. Los bloqueos adquiridos por las conexiones secundarias se mantienen como si los adquiriera la conexión principal y viceversa. Por lo tanto, no se bloquean entre sí.

Detener una transacción

En un escenario de interbloqueo, la transacción víctima se detiene y revierte automáticamente. No es necesario detener una transacción en un escenario de interbloqueo.

Causa de un interbloqueo

Nota:

Este ejemplo funciona en la base de datos AdventureWorksLT2019 con el esquema y los datos predeterminados cuando se ha habilitado READ_COMMITTED_SNAPSHOT. Para descargar este ejemplo, visite Bases de datos de ejemplo AdventureWorks.

Para provocar un interbloqueo, deberá conectar dos sesiones a la base de datos AdventureWorksLT2019. Nos referiremos a estas sesiones como Sesión A y Sesión B. Puede crear estas dos sesiones simplemente creando dos ventanas de consulta en SQL Server Management Studio (SSMS).

En la sesión A, ejecute la siguiente instrucción de Transact-SQL. Este código inicia una transacción explícita y ejecuta una sola instrucción que actualiza la tabla SalesLT.Product. Para ello, la transacción adquiere un bloqueo de actualización (U) en una fila de la tabla SalesLT.Product que se convierte en un bloqueo exclusivo (X). Dejaremos abierta la transacción.

BEGIN TRANSACTION;

UPDATE SalesLT.Product
    SET SellEndDate = SellEndDate + 1
WHERE Color = 'Red';

Ahora, en la sesión B, ejecute la siguiente instrucción de Transact-SQL. Este código no inicia explícitamente una transacción. En su lugar, funciona en modo de transacción de confirmación automática. Esta instrucción actualiza la tabla SalesLT.ProductDescription. La actualización tomará un bloqueo de actualización (U) en 72 filas de la tabla SalesLT.ProductDescription. La consulta se combina con otras tablas, incluida la tabla SalesLT.Product.

UPDATE SalesLT.ProductDescription
    SET Description = Description
FROM SalesLT.ProductDescription AS pd
     INNER JOIN SalesLT.ProductModelProductDescription AS pmpd
         ON pd.ProductDescriptionID = pmpd.ProductDescriptionID
     INNER JOIN SalesLT.ProductModel AS pm
         ON pmpd.ProductModelID = pm.ProductModelID
     INNER JOIN SalesLT.Product AS p
         ON pm.ProductModelID = p.ProductModelID
WHERE p.Color = 'Silver';

Para completar esta actualización, la sesión B necesita un bloqueo compartido (S) en las filas de la tabla SalesLT.Product, incluida la fila bloqueada por la sesión A. La sesión B estará bloqueada en SalesLT.Product.

Vuelva a la sesión A. Ejecute la siguiente instrucción de Transact-SQL. Esto ejecuta una segunda instrucción UPDATE como parte de la transacción abierta.

UPDATE SalesLT.ProductDescription
    SET Description = Description
FROM SalesLT.ProductDescription AS pd
     INNER JOIN SalesLT.ProductModelProductDescription AS pmpd
         ON pd.ProductDescriptionID = pmpd.ProductDescriptionID
     INNER JOIN SalesLT.ProductModel AS pm
         ON pmpd.ProductModelID = pm.ProductModelID
     INNER JOIN SalesLT.Product AS p
         ON pm.ProductModelID = p.ProductModelID
WHERE p.Color = 'Red';

La segunda instrucción de actualización de la sesión A está bloqueada por la sesión B en SalesLT.ProductDescription.

La sesión A y la sesión B ahora se bloquean mutuamente entre sí. Ninguna transacción puede continuar, ya que cada una necesita un recurso bloqueado por la otra.

Después de unos segundos, el monitor de interbloqueo identificará que las transacciones de la sesión A y la sesión B se bloquean mutuamente entre sí y que ninguna puede avanzar. Debería ver que se produce un interbloqueo, con la sesión A elegida como víctima del interbloqueo. La sesión B finaliza correctamente. Aparece un mensaje de error en la sesión A con un texto similar al siguiente:

Msg 1205, Level 13, State 51, Line 7
Transaction (Process ID 51) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Si no se genera un interbloqueo, compruebe que READ_COMMITTED_SNAPSHOT está habilitado en la base de datos de ejemplo. Los interbloqueos se pueden producir en cualquier configuración de base de datos, pero en este ejemplo es necesario habilitar READ_COMMITTED_SNAPSHOT.

A continuación, puede ver los detalles del interbloqueo en el ring_buffer destino de la sesión de eventos extendidos system_health, que está habilitado y activo de manera predeterminada en SQL Server. Considere la siguiente consulta:

WITH cteDeadLocks ([Deadlock_XML])
AS (SELECT CAST (target_data AS XML) AS [Deadlock_XML]
    FROM sys.dm_xe_sessions AS xs
         INNER JOIN sys.dm_xe_session_targets AS xst
             ON xs.[address] = xst.event_session_address
    WHERE xs.[name] = 'system_health'
          AND xst.target_name = 'ring_buffer')
SELECT x.Graph.query('(event/data/value/deadlock)[1]') AS Deadlock_XML,
       x.Graph.value('(event/data/value/deadlock/process-list/process/@lastbatchstarted)[1]', 'datetime2(3)') AS when_occurred,
       DB_Name(x.Graph.value('(event/data/value/deadlock/process-list/process/@currentdb)[1]', 'int')) AS DB --Current database of the first listed process
FROM (SELECT Graph.query('.') AS Graph
      FROM cteDeadLocks AS c
      CROSS APPLY c.[Deadlock_XML].nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS Deadlock_Report(Graph)) AS x
ORDER BY when_occurred DESC;

Puede ver el XML en la columna Deadlock_XML dentro de SSMS seleccionando la celda que aparecerá como hipervínculo. Guarde esta salida como un archivo .xdl, cierre y vuelva a abrir el archivo .xdl en SSMS para el gráfico de interbloqueo visual. Su grafo de interbloqueo debería parecerse al de la imagen siguiente.

Captura de pantalla de un grafo de bloqueo visual en un archivo .xdl en SSMS.

Bloqueos e interbloqueos optimizados

Se aplica a: Azure SQL Database

El bloqueo optimizado ha introducido otro método para la mecánica de bloqueo que cambia cómo se pueden notificar los interbloqueos que implican bloqueos TID exclusivos. En cada recurso <resource-list> del informe de interbloqueo, cada elemento <xactlock> notifica los recursos subyacentes e información específica para los bloqueos de cada miembro de un interbloqueo.

Tenga en cuenta el ejemplo siguiente en el que está habilitado el bloqueo optimizado:

CREATE TABLE t2
(
    a INT PRIMARY KEY NOT NULL,
    b INT NULL
);

INSERT INTO t2
VALUES (1, 10),
(2, 20),
(3, 30);
GO

Los siguientes comandos de Transact-SQL en dos sesiones crearán un interbloqueo en la tabla t2:

En la sesión 1:

--session 1
BEGIN TRANSACTION foo;

UPDATE t2
    SET b = b + 10
WHERE a = 1;

En la sesión 2:

--session 2:
BEGIN TRANSACTION bar;

UPDATE t2
    SET b = b + 10
WHERE a = 2;

En la sesión 1:

--session 1:
UPDATE t2
    SET b = b + 100
WHERE a = 2;

En la sesión 2:

--session 2:
UPDATE t2
    SET b = b + 20
WHERE a = 1;

Este escenario de instrucciones UPDATE enfrentadas da como resultado un interbloqueo. En este caso, un recurso de interbloqueo, donde cada sesión contiene un bloqueo X en su propio TID y espera el bloqueo S en el otro TID, lo que da lugar a un interbloqueo. El siguiente código XML, capturado como informe de interbloqueo, contiene elementos y atributos específicos del bloqueo optimizado:

Captura de pantalla del XML de un informe de bloqueo que muestra los nodos SubyacentesResource y los nodos de bloqueo específicos para el bloqueo optimizado.