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

Exploración de las opciones de espera de bloqueo de baja prioridad en SQL Server 2014 CTP1

SQL Server 2014 CTP1 presenta opciones de espera de bloqueo de baja prioridad para usar con operaciones de índice en línea y conmutadores de partición.

Para aquellos que aprovechan la administración de índices en línea o la partición de índices y las operaciones de cambio de partición en SQL Server 2012 Enterprise Edition, es posible que en algún momento hayan experimentado el bloqueo de su operación DDL, ya que estas operaciones aún tienen algunos requisitos de bloqueo.

Para ilustrar, imagine que ejecuto la siguiente reconstrucción de índice en línea de partición única en SQL Server 2014 CTP1:

ALTER INDEX [ClusteredIndex_on_ps_ShipDate]
ON [dbo].[FactInternetSales]
REBUILD PARTITION = (37)
WITH (ONLINE= ON);

Y echemos un vistazo a los bloqueos adquiridos y liberados durante esta operación de reconstrucción usando eventos extendidos y la siguiente definición de sesión (esta es una sesión sin objetivo y observé los resultados a través del panel "Ver datos en vivo" en SQL Server Management Studio):

CREATE EVENT SESSION [Online_Index_Rebuild_Locks_Taken] ON SERVER 
ADD EVENT sqlserver.lock_acquired(
    WHERE ([object_id]=(309576141))),
ADD EVENT sqlserver.lock_released(
    WHERE ([object_id]=(309576141)))
WITH 
(
  MAX_MEMORY=4096 KB, EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
  MAX_DISPATCH_LATENCY=30 SECONDS, MAX_EVENT_SIZE=0 KB,
  MEMORY_PARTITION_MODE=NONE, TRACK_CAUSALITY=OFF, STARTUP_STATE=OFF
);
GO

El valor 309576141 representa el ID de objeto de la tabla FactInternetSales.

La reconstrucción de mi índice en línea de una sola partición tardó 56 segundos en completarse y, una vez finalizada, vi la siguiente actividad de adquisición y liberación de bloqueos:


Actividad de bloqueo para la reconstrucción en línea de una sola partición

Como puede ver en el resultado, aunque la reconstrucción es una operación en línea, implica la adquisición de bloqueos en varios modos durante el ciclo de vida de la operación. Idealmente, la duración del bloqueo es mínima (por ejemplo, la marca de tiempo es idéntica para el primer SCH_S bloqueo adquirido y liberado). Pero incluso con una cantidad mínima de bloqueo, ciertamente puede encontrar problemas de simultaneidad dependiendo de las transacciones que se ejecutan en el índice que se está reconstruyendo o cambiando.

Mencioné al comienzo de esta publicación que Microsoft introdujo opciones de espera de bloqueo de baja prioridad para operaciones en línea y operaciones de cambio de partición en SQL Server 2014 CTP1. Sobre el tema de los interruptores de partición, imagine que ejecuto la siguiente operación:

ALTER TABLE [AdventureWorksDW2012].[dbo].[FactInternetSales] 
SWITCH PARTITION 37 TO  [AdventureWorksDW2012].[dbo].[staging_FactInternetSales];

Para ver los bloqueos adquiridos y liberados para esta operación, modifiqué mi sesión de eventos extendidos previamente definida para incluir los objetos aplicables (tabla de origen y de destino). Vi lo siguiente:


Actividad de bloqueo para una operación de cambio de partición

La operación de cambio a una partición vacía ocurrió en menos de un segundo, pero aún vemos que SCH_S y SCH_M se requirieron bloqueos durante el ciclo de vida de la operación tanto en el origen como en el destino (309576141 siendo FactInternetSales y 398624463 siendo staging_FactInternetSales).

Entonces, nuevamente, si bien la duración del bloqueo puede ser extremadamente breve cuando no hay transacciones simultáneas que accedan a los objetos en cuestión, sabemos que esto no siempre es posible y, por lo tanto, nuestras operaciones de cambio de partición y reconstrucción de índice en línea pueden bloquearse.

Entonces, con esta realidad, SQL Server 2014 presenta el WAIT_AT_LOW_PRIORITY argumento que se puede ajustar con MAX_DURATION y ABORT_AFTER_WAIT opciones tanto para ALTER INDEX y ALTER TABLE comandos que podemos usar tanto para el índice en línea como para las operaciones de cambio de partición.

¿Qué nos permite hacer esto? En primer lugar, hablemos de cuál era el comportamiento antes de SQL Server 2014. Como ejemplo, imagine que tengo la siguiente transacción abierta y no confirmada:

BEGIN TRANSACTION;
DELETE [dbo].[staging_FactInternetSales];

Si traté de realizar un ALTER TABLE SWITCH a la tabla staging_FactInternetSales como destino en una sesión separada, me bloquearán y la solicitud solo esperará. Específicamente para este ejemplo, estaría esperando con un LCK_M_SCH_M tipo de espera. Una vez que retrocedo o confirmo mi transacción, la operación puede avanzar y completarse.

Ahora, si estoy usando WAIT_AT_LOW_PRIORITY de SQL Server 2014 con MAX_DURATION y ABORT_AFTER_WAIT , puedo aprovechar algunas opciones diferentes según los requisitos de mi aplicación.

MAX_DURATION me permite especificar la cantidad de minutos que esperará la reconstrucción del índice en línea o la operación de cambio de partición. Si la MAX_DURATION se alcanza el valor, podemos establecer lo que sucede a continuación en función de la configuración de ABORT_AFTER_WAIT , que puede ser un valor de NONE , SELF o BLOCKERS :

  • NONE significa que la operación de índice continuará intentando la operación.
  • SELF significa que si la MAX_DURATION se alcanza, la operación (la reconstrucción del índice en línea o el cambio de partición) se cancelará.
  • Si BLOCKERS se usa, eliminará cualquier transacción que esté bloqueando la reconstrucción del índice en línea o la operación de cambio de partición (no es una opción, en mi opinión, para usar a la ligera). BLOCKERS también requiere ALTER ANY CONNECTION permiso para la solicitud que emite la reconstrucción del índice en línea o la operación de cambio de partición.

Los siguientes ejemplos de código muestran diferentes variaciones de configuración.

    Comportamiento predeterminado anterior a 2014 (esperar indefinidamente)

      Ejecutar lo siguiente dará como resultado el comportamiento al que estamos acostumbrados a ver antes de SQL Server 2014, y aún podría ser lo que deseará o esperará para ciertos escenarios:

      ALTER TABLE [AdventureWorksDW2012].[dbo].[FactInternetSales] 
      SWITCH PARTITION 37 TO  [AdventureWorksDW2012].[dbo].[staging_FactInternetSales] 
      WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 0 MINUTES, ABORT_AFTER_WAIT = NONE));

    Espere 1 minuto y cancele la operación DDL

      El siguiente ejemplo espera 1 minuto si hay una transacción de bloqueo y obtendrá un "período de tiempo de espera de solicitud de bloqueo excedido" para el SWITCH operación si se alcanza la duración máxima:

      ALTER TABLE [AdventureWorksDW2012].[dbo].[FactInternetSales] 
      SWITCH PARTITION 37 TO  [AdventureWorksDW2012].[dbo].[staging_FactInternetSales] 
      WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF));

    Espere 1 minuto y elimine a los bloqueadores

      Este ejemplo espera 1 minuto si hay una transacción de bloqueo y luego eliminará las transacciones de bloqueo (origen o destino incluido), permitiendo el SWITCH operación para completar.

      ALTER TABLE [AdventureWorksDW2012].[dbo].[staging_FactInternetSales] 
      SWITCH PARTITION 37 TO  [AdventureWorksDW2012].[dbo].[FactInternetSales] 
      WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = BLOCKERS));

      En mi ejemplo de un DELETE dentro de una transacción no confirmada, no hubo ningún error en mi ventana de SQL Server Management Studio ya que no tenía una declaración en ejecución activa, pero intentar otra declaración dentro de esa sesión devolvió el siguiente mensaje de error (ya que mi sesión había sido cancelada):

      Mensaje 233, Nivel 20, Estado 0, Línea 3
      Se produjo un error de nivel de transporte al enviar la solicitud al servidor. (proveedor:proveedor de memoria compartida, error:0:no hay ningún proceso en el otro extremo de la tubería).

    Elimine a los bloqueadores inmediatamente (fuente o destino para SWITCH)

      El siguiente es un ejemplo de cómo eliminar el bloqueador de inmediato, y en mi ejemplo, el cambio ocurrió en menos de un segundo y, de hecho, la sesión que bloqueaba se eliminó:

      ALTER TABLE [AdventureWorksDW2012].[dbo].[FactInternetSales] 
      SWITCH PARTITION 37 TO  [AdventureWorksDW2012].[dbo].[staging_FactInternetSales]
      WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 0 MINUTES, ABORT_AFTER_WAIT = BLOCKERS));

Un último aspecto positivo que quería destacar...

El registro de errores de SQL Server proporciona una auditoría predeterminada del uso de espera de bloqueo de baja prioridad, incluida información sobre ABORT_AFTER_WAIT operación en línea con la información de la víctima:

Fecha 10/09/2013 1:37:15 p. ID 57 fue eliminado por una instrucción ABORT_AFTER_WAIT =BLOCKERS DDL en database_id =5, object_id =309576141.

Y también verá entradas separadas para la operación original en sí. Por ejemplo:

Se ejecutó una instrucción ALTER TABLE SWITCH en la base de datos 'AdventureWorksDW2012', tabla 'staging_FactInternetSales' con el nombre de host 'WIN-4T7S36VMSD9', ID de proceso de host 1360 con la tabla de destino 'AdventureWorksDW2012.dbo.FactInternetSales' usando las opciones WAIT_AT_LOW_PRIORITY con MAX_DURATION =1 y ABORT =_AFTER_WAIT BLOQUEADORES. El bloqueo de sesiones de usuario se eliminará después de la duración máxima del tiempo de espera.

Este tipo de registro es muy útil para solucionar problemas y realizar auditorías, y me alegra verlo.