sql >> Base de Datos >  >> RDS >> Sqlserver

La anatomía de los interbloqueos de SQL Server y las mejores formas de evitarlos

Los profesionales de las bases de datos se enfrentan de forma rutinaria a problemas de rendimiento de las bases de datos, como una indexación incorrecta y un código mal escrito en instancias SQL de producción. Suponga que actualizó una transacción y SQL Server informó el siguiente mensaje de interbloqueo. Para los administradores de bases de datos que recién comienzan, esto podría ser una sorpresa.

En este artículo, exploraremos los interbloqueos de SQL Server y las mejores formas de evitarlos.

¿Qué es un interbloqueo de SQL Server?

SQL Server es una base de datos altamente transaccional. Por ejemplo, suponga que está respaldando la base de datos de un portal de compras en línea donde recibe nuevos pedidos de clientes durante todo el día. Es probable que varios usuarios realicen la misma actividad al mismo tiempo. En este caso, su base de datos debe seguir las propiedades de Atomicidad, Consistencia, Aislamiento, Durabilidad (ACID) para ser consistente, confiable y proteger la integridad de los datos.

La siguiente imagen describe las propiedades ACID en una base de datos relacional.

Para seguir las propiedades de ACID, SQL Server utiliza mecanismos de bloqueo, restricciones y registro de escritura anticipada. Varios tipos de bloqueo incluyen:bloqueo exclusivo (X), bloqueo compartido (S), bloqueo de actualización (U), bloqueo de intención (I), bloqueo de esquema (SCH) y bloqueo de actualización masiva (BU). Estos bloqueos se pueden adquirir a nivel de clave, tabla, fila, página y base de datos.

Suponga que tiene dos usuarios, John y Peter, que están conectados a la base de datos de clientes.

  • John quiere actualizar los registros del cliente que tiene [customerid] 1.
  • Al mismo tiempo, Peter quiere recuperar el valor para el cliente que tiene [customerid] 1.

En este caso, SQL Server usa los siguientes bloqueos tanto para John como para Peter.

Cerraduras para John

  • Se necesita un bloqueo de intento exclusivo (IX) en la tabla de clientes y la página que contiene el registro.
  • Además, requiere un bloqueo exclusivo (X) en la fila que John quiere actualizar. Impide que cualquier otro usuario modifique los datos de la fila hasta que el proceso A libere su bloqueo.

Cerraduras para Peter

  • Adquiere un bloqueo de intención compartida (IS) en la tabla de clientes y la página que contiene el registro según la cláusula where.
  • Intenta tomar un candado compartido para leer la fila. Esta fila ya tiene un candado exclusivo para John.

En este caso, Peter debe esperar hasta que John termine su trabajo y libere el bloqueo exclusivo. Esta situación se conoce como bloqueo.

Ahora, supongamos que en otro escenario, John y Peter tienen los siguientes candados.

  • John tiene un bloqueo exclusivo en la tabla de clientes para el ID de cliente 1.
  • Peter tiene un bloqueo exclusivo en la tabla de pedidos para el ID de cliente 1.
  • John requiere un bloqueo exclusivo en la tabla de pedidos para finalizar su transacción. Peter ya tiene un bloqueo exclusivo en la tabla de pedidos.
  • Peter requiere un candado exclusivo en la tabla de clientes para finalizar su transacción. John ya tiene un candado exclusivo en la mesa de clientes.

En este caso, ninguna de las transacciones puede continuar porque cada transacción requiere un recurso en poder de la otra transacción. Esta situación se conoce como interbloqueo de SQL Server.

Mecanismos de supervisión de puntos muertos de SQL Server

SQL Server supervisa las situaciones de interbloqueo periódicamente mediante el subproceso del monitor de interbloqueo. Esto verifica los procesos involucrados en un interbloqueo e identifica si una sesión se ha convertido en una víctima del interbloqueo. Utiliza un mecanismo interno para identificar el proceso víctima del punto muerto. De forma predeterminada, la transacción con la menor cantidad de recursos necesarios para la reversión se considera víctima.

SQL Server elimina la sesión de la víctima para que otra sesión pueda adquirir el bloqueo necesario para completar su transacción. De forma predeterminada, SQL Server comprueba la situación de interbloqueo cada 5 segundos mediante el monitor de interbloqueo. Si detecta un interbloqueo, podría reducir la frecuencia de 5 segundos a 100 milisegundos dependiendo de la ocurrencia del interbloqueo. Vuelve a restablecer el subproceso de supervisión a 5 segundos si no se producen interbloqueos frecuentes.

Una vez que SQL Server elimina un proceso como víctima de punto muerto, recibirá el siguiente mensaje. En esta sesión, el proceso ID 69 fue víctima de interbloqueo.

Los impactos del uso de declaraciones de prioridad de interbloqueo de SQL Server

De forma predeterminada, SQL Server marca la transacción con la reversión menos costosa como víctima de interbloqueo. Los usuarios pueden establecer la prioridad de interbloqueo en una transacción utilizando la instrucción DEADLOCK_PRIORITY.

SET DEADLOCK_PRIORITY

Utiliza los siguientes argumentos:

  • Bajo:Es equivalente a la prioridad de interbloqueo -5
  • Normal:es la prioridad de interbloqueo predeterminada 0
  • Alta:Es la prioridad 5 de interbloqueo más alta.

También podemos establecer valores numéricos para la prioridad de punto muerto de -10 a 10 (21 valores en total).

Veamos algunos ejemplos de declaraciones de prioridad de interbloqueo.

Ejemplo 1:

Sesión 1 con prioridad de interbloqueo:Normal (0)> Sesión 2 con prioridad de interbloqueo:Baja (-5)

Víctima de interbloqueo:  Sesión 2

Ejemplo 2:

Sesión 1 con prioridad de interbloqueo:Normal (0)

Víctima de interbloqueo:  Sesión 1

Ejemplo 3

Sesión 1 con prioridad de interbloqueo:-3> Sesión 2 con prioridad de interbloqueo:-7

Ejemplo 4:

Sesión 1 con prioridad de interbloqueo:-5

Víctima de interbloqueo:  Sesión 1

Interbloqueos de SQL Server utilizando gráficos de interbloqueos

Un gráfico de interbloqueo es una representación visual de los procesos de interbloqueo, sus bloqueos y la víctima del interbloqueo. Podemos habilitar los indicadores de rastreo 1204 y 1222 para capturar información detallada de punto muerto en un formato XML y gráfico. Podemos usar el evento extendido predeterminado system_health para obtener los detalles del interbloqueo. Una forma rápida y sencilla de interpretar el interbloqueo es a través de un gráfico de interbloqueo. Simulemos una condición de punto muerto y veamos su gráfico de punto muerto correspondiente.

Para esta demostración, creamos la tabla Cliente y Pedidos e insertamos algunos registros de muestra.

CREATE TABLE Customer (ID INT IDENTITY(1,1), CustomerName VARCHAR(20)) GO CREATE TABLE Orders (OrderID INT IDENTITY(1,1), ProductName VARCHAR(50)) GO INSERT INTO Customer(CustomerName) VALUES ('Rajendra') Go 100 S INSERT INTO Orders(ProductName) VALUES ('Laptop') Go 100

Luego, abrimos una nueva ventana de consulta y habilitamos el indicador de rastreo globalmente.

Rastreo DBCC (1222,-1)

Una vez que habilitamos el indicador de seguimiento de interbloqueo, comenzamos dos sesiones y ejecutamos la consulta en el siguiente orden:

  • La primera sesión inicia una transacción para actualizar la tabla de clientes para el ID de cliente 1.
  • La segunda sesión inicia una transacción para actualizar la tabla de pedidos para el ID de pedido 10.
  • La primera sesión intenta actualizar la tabla de pedidos para el mismo ID de pedido 10. La segunda sesión ya bloquea esta fila. La sesión 1 está bloqueada debido a los bloqueos realizados por la sesión 2.
  • Ahora, para la sesión 2, queremos actualizar la tabla de clientes para el ID de cliente 1. Genera una situación de interbloqueo en la que las sesiones ID 63 e ID 65 no pueden progresar.

En este ejemplo, SQL Server elige una víctima de interbloqueo (ID de sesión 65) y elimina la transacción. Busquemos el gráfico de interbloqueo de la sesión de eventos extendidos system_health.

SELECT XEvent.query('(event/data/value/deadlock)[1]') AS DeadlockGraph FROM ( SELECT XEvent.query('.') AS XEvent FROM ( SELECT CAST(target_data AS XML) AS TargetData FROM sys.dm_xe_session_targets st INNER JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address WHERE s.NAME = ‘system_health’ AND st.target_name = ‘ring_buffer’ ) AS Data CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"] ') AS XEventData(XEvent) ) AS source;

Esta consulta nos da un XML de interbloqueo que requiere un DBA experimentado para interpretar la información.

Guardamos este XML de interbloqueo usando la extensión .XDL y cuando abrimos el archivo XDL en SSMS, obtenemos el gráfico de interbloqueo que se muestra a continuación.

Este gráfico de punto muerto proporciona la siguiente información:

  • Nodos de proceso:  En el óvalo, obtiene información relacionada con el proceso.
  • Nodos de recursos:  Los nodos de recursos (cuadro cuadrado) brindan información sobre los objetos involucrados en las transacciones junto con los bloqueos. En este ejemplo, muestra bloqueos RID porque no tenemos índices para ambas tablas.
  • Bordes:  Un borde conecta el nodo de proceso y el nodo de recurso. Muestra el propietario del recurso y el modo de bloqueo de la solicitud.

Representa a una víctima de interbloqueo tachando el óvalo en el gráfico de interbloqueo.

Puede capturar información de interbloqueo de SQL Server de las siguientes maneras:

  • Generador de perfiles de SQL Server
  • Eventos extendidos de SQL Server
  • Registros de errores de SQL Server
  • Trazas predeterminadas en SQL Server

5 tipos de interbloqueos en SQL Server

1) Bloqueo de búsqueda de marcadores

La búsqueda de marcadores es un punto muerto que se encuentra comúnmente en SQL Server. Ocurre debido a un conflicto entre la declaración de selección y las declaraciones DML (insertar, actualizar y eliminar). Por lo general, SQL Server elige la declaración de selección como víctima de interbloqueo porque no provoca cambios en los datos y la reversión es rápida. Para evitar la búsqueda de marcadores, puede utilizar un índice de cobertura. También puede usar una sugerencia de consulta NOLOCK en las instrucciones de selección, pero lee datos no confirmados.

2) Punto muerto de escaneo de rango

A veces, usamos un nivel de aislamiento SERIALIZABLE a nivel de servidor o de sesión. Es un nivel de aislamiento restrictivo para el control de simultaneidad y puede crear bloqueos de escaneo de rango en lugar de bloqueos de nivel de página o fila. En el nivel de aislamiento SERIALIZABLE, los usuarios no pueden leer los datos si se modifican pero esperan ser confirmados en una transacción. De manera similar, si una transacción lee datos, otra transacción no puede modificarlos. Proporciona la concurrencia más baja, por lo que deberíamos usar este nivel de aislamiento en requisitos de aplicaciones específicas.

3) Interbloqueo de restricción en cascada

SQL Server usa la relación padre-hijo entre tablas usando las restricciones de clave externa. En este escenario, si actualizamos o eliminamos un registro de la tabla principal, se requieren los bloqueos necesarios en la tabla secundaria para evitar registros huérfanos. Para eliminar estos interbloqueos, siempre debe modificar primero los datos en una tabla secundaria y luego los datos principales. También puede trabajar directamente con la tabla principal utilizando las opciones ELIMINAR CASCADA o ACTUALIZAR CASCADA. También debe crear índices apropiados en las columnas de clave externa.

4) Punto muerto de paralelismo intra-consulta

Una vez que un usuario envía una consulta al motor de consultas SQL, el optimizador de consultas crea un plan de ejecución optimizado. Puede ejecutar la consulta en orden serial o paralelo dependiendo del costo de la consulta, el grado máximo de paralelismo (MAXDOP) y el umbral de costo para el paralelismo.

En un modo de paralelismo, SQL Server asigna varios subprocesos. A veces, para una consulta grande en modo de paralelismo, estos subprocesos comienzan a bloquearse entre sí. Eventualmente, se convierte en puntos muertos. En este caso, debe revisar el plan de ejecución y su MAXDOP y umbral de costo para las configuraciones de paralelismo. También puede especificar el MAXDOP a nivel de sesión para solucionar el escenario de interbloqueo.

5) Bloqueo inverso del orden de los objetos

En este tipo de interbloqueo, múltiples transacciones acceden a objetos en un orden diferente en el T-SQL. Esto provoca el bloqueo entre los recursos de cada sesión y lo convierte en un interbloqueo. Siempre desea acceder a los objetos en un orden lógico para que no conduzca a una situación de punto muerto.

Maneras útiles de evitar y minimizar los interbloqueos de SQL Server

  • Trate de que las transacciones sean cortas; esto evitará mantener bloqueos en una transacción durante un largo período de tiempo.
  • Acceda a objetos de una manera lógica similar en múltiples transacciones.
  • Cree un índice de cobertura para reducir la posibilidad de un interbloqueo.
  • Cree índices para que coincidan con las columnas de clave externa. De esta manera, puede eliminar interbloqueos debido a la integridad referencial en cascada.
  • Establezca prioridades de punto muerto mediante la variable de sesión SET DEADLOCK_PRIORITY. Si establece la prioridad de interbloqueo, SQL Server finaliza la sesión con la prioridad de interbloqueo más baja.
  • Utilice el manejo de errores usando los bloques try-catch. Puede atrapar el error de interbloqueo y volver a ejecutar la transacción en caso de una víctima de interbloqueo.
  • Cambie el nivel de aislamiento a READ COMMITTED SNAPSHOT AISLATION o SNAPSHOT AISLATION. Esto cambia el mecanismo de bloqueo de SQL Server. Sin embargo, debe tener cuidado al cambiar el nivel de aislamiento, ya que podría afectar negativamente a otras consultas.

Consideraciones sobre puntos muertos de SQL Server

Los interbloqueos son un mecanismo natural en SQL Server para evitar que la sesión mantenga bloqueos y espere otros recursos. Debe capturar las consultas de interbloqueo y optimizarlas para que no entren en conflicto entre sí. Es importante capturar el bloqueo durante un período corto y liberarlo, para que otras consultas puedan usarlo de manera efectiva.

Los interbloqueos de SQL Server ocurren, y aunque SQL Server maneja internamente las situaciones de interbloqueo, debe intentar minimizarlas siempre que sea posible. Algunas de las mejores formas de eliminar los interbloqueos son crear un índice, aplicar cambios en el código de la aplicación o inspeccionar cuidadosamente los recursos en un gráfico de interbloqueos. Para obtener más consejos sobre cómo evitar bloqueos de SQL, consulte nuestra publicación: Evitar bloqueos de SQL con el ajuste de consultas.