Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Explorando opções de espera de bloqueio de baixa prioridade no SQL Server 2014 CTP1


O SQL Server 2014 CTP1 apresenta opções de espera de bloqueio de baixa prioridade para uso com operações de índice online e comutadores de partição.

Para aqueles que utilizam o gerenciamento de índice online ou particionamento de índice e operações de alternância de partição no SQL Server 2012 Enterprise Edition, você pode ter experimentado em um ponto o bloqueio de sua operação DDL, pois essas operações ainda têm alguns requisitos de bloqueio.

Para ilustrar, imagine que eu execute a seguinte reconstrução de índice online de partição única no SQL Server 2014 CTP1:
ALTER INDEX [ClusteredIndex_on_ps_ShipDate]
ON [dbo].[FactInternetSales]
REBUILD PARTITION = (37)
WITH (ONLINE= ON);

E vamos dar uma olhada nos bloqueios adquiridos e liberados durante esta operação de reconstrução usando Extended Events e a seguinte definição de sessão (esta é uma sessão sem destino e observei os resultados por meio do painel “Watch Live Data” no 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

O valor 309576141 representa a identificação do objeto da tabela FactInternetSales.

Minha reconstrução de índice online de uma única partição levou 56 segundos para ser concluída e, após a conclusão, vi a seguinte atividade de aquisição e liberação de bloqueio:


Atividade de bloqueio para reconstrução online de partição única

Como você pode ver na saída, embora a reconstrução seja uma operação online, ela envolve a aquisição de bloqueios em vários modos durante o ciclo de vida da operação. Idealmente, a duração do bloqueio é mínima (por exemplo – o carimbo de data/hora é idêntico para o primeiro SCH_S bloqueio adquirido e liberado). Mas mesmo com uma quantidade mínima de bloqueio, você certamente pode encontrar problemas de simultaneidade, dependendo das transações executadas no índice que está sendo reconstruído ou alterado.

Mencionei no início deste post que a Microsoft introduziu opções de espera de bloqueio de baixa prioridade para operações online e operações de alternância de partição no SQL Server 2014 CTP1. Sobre o assunto de comutadores de partição, imagine que eu execute a seguinte operação:
ALTER TABLE [AdventureWorksDW2012].[dbo].[FactInternetSales] 
SWITCH PARTITION 37 TO  [AdventureWorksDW2012].[dbo].[staging_FactInternetSales];

Para ver os bloqueios adquiridos e liberados para esta operação, modifiquei minha sessão Extended Event definida anteriormente para incluir os objetos aplicáveis ​​(tabela de origem e destino). Eu vi o seguinte:


Atividade de bloqueio para uma operação de troca de partição

A operação de troca para uma partição vazia ocorreu em menos de um segundo, mas ainda vemos que SCH_S e SCH_M bloqueios eram necessários durante o ciclo de vida da operação na origem e no destino (309576141 sendo FactInternetSales e 398624463 sendo staging_FactInternetSales).

Então, novamente, embora a duração do bloqueio possa ser extremamente breve quando não há transações simultâneas acessando os objetos em questão, sabemos que isso nem sempre é possível e, portanto, nossas operações de reconstrução de índice online e troca de partição podem realmente ser bloqueadas.

Assim, com essa realidade, o SQL Server 2014 apresenta o WAIT_AT_LOW_PRIORITY argumento que pode ser ajustado com MAX_DURATION e ABORT_AFTER_WAIT opções para o ALTER INDEX e ALTER TABLE comandos que podemos usar tanto para indexação online quanto para operações de alternância de partição.

O que isso nos permite fazer? Antes de tudo, vamos falar sobre como era o comportamento antes do SQL Server 2014. Como exemplo, imagine que eu tenha a seguinte transação aberta e não confirmada:
BEGIN TRANSACTION;
DELETE [dbo].[staging_FactInternetSales];

Se eu tentasse executar um ALTER TABLE SWITCH para a tabela staging_FactInternetSales como destino em uma sessão separada, serei bloqueado e a solicitação ficará apenas esperando. Especificamente para este exemplo, eu estaria esperando com um LCK_M_SCH_M tipo de espera. Depois de reverter ou confirmar minha transação, a operação pode avançar e ser concluída.

Agora, se estou usando o WAIT_AT_LOW_PRIORITY do SQL Server 2014 com MAX_DURATION e ABORT_AFTER_WAIT , posso aproveitar algumas opções diferentes, dependendo dos requisitos do meu aplicativo.

MAX_DURATION permite especificar o número de minutos que a reconstrução do índice online ou a operação de troca de partição aguardará. Se o MAX_DURATION valor for atingido, podemos definir o que acontece a seguir com base na configuração de ABORT_AFTER_WAIT , que pode ser um valor de NONE , SELF ou BLOCKERS :
  • NONE significa que a operação de índice continuará tentando a operação.
  • SELF significa que se o MAX_DURATION for atingido, a operação (a reconstrução do índice online ou a troca de partição) será cancelada.
  • Se BLOCKERS for usado, ele matará todas as transações que estão bloqueando a reconstrução do índice online ou a operação de troca de partição (não é uma opção, na minha opinião, a ser usada levemente). BLOCKERS também requer ALTER ANY CONNECTION permissão para a solicitação que emite a reconstrução do índice online ou a operação de troca de partição.

Os exemplos de código a seguir demonstram diferentes variações de configuração.

    Comportamento padrão anterior a 2014 (aguardar indefinidamente)

      Executar o seguinte resultará no comportamento que estamos acostumados a ver antes do SQL Server 2014 – e ainda pode ser o que você deseja ou espera para determinados cenários:
      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));

    Aguarde 1 minuto e cancele a operação DDL

      O exemplo a seguir aguarda 1 minuto se houver uma transação de bloqueio e obterá um "período de tempo limite de solicitação de bloqueio excedido" para o SWITCH operação se a duração máxima for atingida:
      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 e mate o(s) bloqueador(es)

      Este exemplo espera 1 minuto se houver uma transação de bloqueio e, em seguida, eliminará as transações de bloqueio (origem ou destino incluído), permitindo o SWITCH operação para ser concluída.
      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));

      No meu exemplo de um DELETE dentro de uma transação não confirmada, não houve erro na minha janela do SQL Server Management Studio, pois eu não tinha uma instrução em execução ativa, mas tentar outra instrução nessa sessão retornou a seguinte mensagem de erro (já que minha sessão foi encerrada):
      Msg 233, Level 20, State 0, Line 3
      Ocorreu um erro de nível de transporte ao enviar a solicitação ao servidor. (provedor:Provedor de Memória Compartilhada, erro:0 – Nenhum processo está na outra extremidade do canal.)

    Mate o(s) Bloqueador(es) Imediatamente (Fonte ou Destino para SWITCH)

      O seguinte é um exemplo de matar o bloqueador imediatamente – e no meu exemplo a troca aconteceu em menos de um segundo e, de fato, a sessão que era o bloqueador foi morta:
      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));

Um último aspecto positivo que eu queria destacar…

O log de erros do SQL Server fornece algumas auditorias padrão do uso de espera de bloqueio de baixa prioridade, incluindo informações sobre o ABORT_AFTER_WAIT operação em linha com as informações da vítima:
Data 10/09/2013 13:37:15
Log SQL Server (Atual – 10/09/2013 12:03:00)
Fonte spid51
Mensagem
Processo ID 57 foi morto por uma instrução ABORT_AFTER_WAIT =BLOCKERS DDL em database_id =5, object_id =309576141.
E você também verá entradas separadas para a própria operação original. Por exemplo:
Uma instrução ALTER TABLE SWITCH foi executada no banco de dados 'AdventureWorksDW2012', tabela 'staging_FactInternetSales' pelo nome do host 'WIN-4T7S36VMSD9', ID do processo do host 1360 com a tabela de destino 'AdventureWorksDW2012.dbo.FactInternetSales' usando as opções WAIT_AT_LOW_PRIORITY com MAX_DURATION =1 e ABORT_AFTER_WAIT =1 e ABORT_AFTER_WAIT =1 BLOQUEADORES. O bloqueio de sessões de usuário será eliminado após a duração máxima do tempo de espera.
Esse tipo de registro é muito útil para fins de solução de problemas e auditoria e fico feliz em vê-lo.