Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Esplorazione delle opzioni di attesa del blocco con priorità bassa in SQL Server 2014 CTP1

SQL Server 2014 CTP1 introduce opzioni di attesa di blocco a bassa priorità da utilizzare con operazioni sugli indici online e opzioni di partizione.

Per coloro che sfruttano la gestione dell'indice online o il partizionamento dell'indice e le operazioni di cambio di partizione in SQL Server 2012 Enterprise Edition, a un certo punto potresti aver riscontrato il blocco dell'operazione DDL poiché queste operazioni richiedono ancora alcuni requisiti di blocco.

Per illustrare, immagina di eseguire la seguente ricostruzione dell'indice online a partizione singola in SQL Server 2014 CTP1:

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

E diamo un'occhiata ai blocchi acquisiti e rilasciati durante questa operazione di ricostruzione utilizzando gli eventi estesi e la seguente definizione di sessione (questa è una sessione senza destinazione e ho osservato i risultati tramite il riquadro "Guarda dati in tempo reale" in 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

Il valore 309576141 rappresenta l'ID oggetto della tabella FactInternetSales.

Il completamento della ricostruzione dell'indice online di una singola partizione ha richiesto 56 secondi e, dopo il completamento, ho visto la seguente attività di acquisizione e rilascio del blocco:


Blocca l'attività per la ricostruzione online di partizioni singole

Come puoi vedere dall'output, sebbene la ricostruzione sia un'operazione online, implica l'acquisizione di blocchi in varie modalità durante il ciclo di vita dell'operazione. Idealmente la durata del blocco è minima (ad esempio, il timestamp è identico per il primo SCH_S serratura acquisita e sbloccata). Ma anche con una quantità minima di blocco, puoi sicuramente riscontrare problemi di concorrenza a seconda delle transazioni in esecuzione sull'indice che viene ricostruito o inserito.

Ho menzionato all'inizio di questo post che Microsoft ha introdotto opzioni di attesa di blocco a bassa priorità per le operazioni online e le operazioni di cambio di partizione in SQL Server 2014 CTP1. A proposito di cambi di partizione, immagina di eseguire la seguente operazione:

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

Per vedere i lock acquisiti e rilasciati per questa operazione, ho modificato la mia sessione di eventi estesi precedentemente definita per includere gli oggetti applicabili (tabella di origine e di destinazione). Ho visto quanto segue:


Attività di blocco per un'operazione di cambio di partizione

L'operazione di passaggio a una partizione vuota è avvenuta in meno di un secondo, ma vediamo ancora che SCH_S e SCH_M erano necessari blocchi durante il ciclo di vita dell'operazione sia sull'origine che sulla destinazione (309576141 era FactInternetSales e 398624463 era staging_FactInternetSales).

Quindi, ancora una volta, mentre la durata del blocco può essere estremamente breve quando non ci sono transazioni simultanee che accedono agli oggetti in questione, sappiamo che ciò non è sempre possibile e quindi le nostre operazioni di ricostruzione dell'indice online e cambio di partizione possono effettivamente essere bloccate.

Quindi, con questa realtà, SQL Server 2014 introduce il WAIT_AT_LOW_PRIORITY argomento che può essere modificato con MAX_DURATION e ABORT_AFTER_WAIT opzioni per entrambi ALTER INDEX e ALTER TABLE comandi che possiamo usare sia per l'indice online che per le operazioni di cambio di partizione.

Cosa ci permette di fare? Prima di tutto, parliamo del comportamento prima di SQL Server 2014. Ad esempio, immagina di avere la seguente transazione aperta e non vincolata:

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

Se ho provato a eseguire un ALTER TABLE SWITCH alla tabella staging_FactInternetSales come destinazione in una sessione separata, verrò bloccato e la richiesta aspetterà. In particolare per questo esempio, aspetterei con un LCK_M_SCH_M tipo di attesa. Una volta eseguito il rollback o il commit della transazione, l'operazione può andare avanti e completarsi.

Ora, se sto usando WAIT_AT_LOW_PRIORITY di SQL Server 2014 con MAX_DURATION e ABORT_AFTER_WAIT , posso sfruttare alcune opzioni diverse a seconda dei requisiti della mia applicazione.

MAX_DURATION mi consente di specificare il numero di minuti di attesa dell'operazione di ricostruzione dell'indice o di cambio di partizione in linea. Se il MAX_DURATION viene raggiunto il valore, possiamo impostare cosa succede dopo in base all'impostazione di ABORT_AFTER_WAIT , che può essere un valore di NONE , SELF o BLOCKERS :

  • NONE significa che l'operazione sull'indice continuerà a tentare l'operazione.
  • SELF significa che se il MAX_DURATION viene raggiunta, l'operazione (ricostruzione dell'indice in linea o cambio di partizione) verrà annullata.
  • Se BLOCKERS viene utilizzato, ucciderà tutte le transazioni che stanno bloccando l'operazione di ricostruzione dell'indice online o cambio di partizione (non un'opzione, a mio avviso, da usare alla leggera). BLOCKERS richiede anche ALTER ANY CONNECTION autorizzazione per la richiesta che emette l'operazione di ricostruzione dell'indice o cambio di partizione in linea.

Gli esempi di codice seguenti mostrano diverse varianti di configurazione.

    Comportamento predefinito prima del 2014 (attendi a tempo indeterminato)

      L'esecuzione di quanto segue risulterà nel comportamento che siamo abituati a vedere prima di SQL Server 2014 e potrebbe essere comunque quello che vorrai o ti aspetti per determinati scenari:

      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));

    Attendere 1 minuto e annullare l'operazione DDL

      L'esempio seguente attende 1 minuto se c'è una transazione bloccante e riceverà un "periodo di timeout della richiesta di blocco superato" per il SWITCH operazione al raggiungimento della durata massima:

      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));

    Aspetta 1 minuto e uccidi i bloccanti

      Questo esempio attende 1 minuto se c'è una transazione bloccante e quindi interromperà le transazioni bloccanti (origine o destinazione incluse), consentendo il SWITCH operazione da completare.

      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));

      Nel mio esempio di DELETE all'interno di una transazione non vincolata, non si è verificato alcun errore nella finestra di SQL Server Management Studio poiché non avevo un'istruzione in esecuzione attivamente, ma il tentativo di un'altra istruzione all'interno di quella sessione ha restituito il seguente messaggio di errore (poiché la mia sessione era stata interrotta):

      Msg 233, livello 20, stato 0, riga 3
      Si è verificato un errore a livello di trasporto durante l'invio della richiesta al server. (provider:Shared Memory Provider, errore:0 – Nessun processo è presente all'altra estremità della pipe.)

    Uccidi immediatamente i bloccanti (fonte o destinazione di SWITCH)

      Quello che segue è un esempio di eliminazione immediata del bloccante, e nel mio esempio il passaggio è avvenuto in meno di un secondo e in effetti la sessione che era il bloccante è stata uccisa:

      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 ultimo aspetto positivo che volevo richiamare…

Il registro degli errori di SQL Server fornisce alcuni controlli predefiniti dell'utilizzo dell'attesa di blocco a bassa priorità, incluse le informazioni su ABORT_AFTER_WAIT operazione in linea con le informazioni sulla vittima:

Data 9/10/2013 13:37:15
Registra SQL Server (corrente – 9/10/2013 12:03:00)
Sorgente spid51
Messaggio
Processo L'ID 57 è stato interrotto da un'istruzione ABORT_AFTER_WAIT =BLOCKERS DDL su database_id =5, object_id =309576141.

E vedrai anche voci separate per l'operazione originale stessa. Ad esempio:

Un'istruzione ALTER TABLE SWITCH è stata eseguita sul database 'AdventureWorksDW2012', tabella 'staging_FactInternetSales' per nome host 'WIN-4T7S36VMSD9', ID processo host 1360 con tabella di destinazione 'AdventureWorksDW2012.dbo.FactInternetSales' utilizzando le opzioni WAIT_AT_LOW_PRIORITY con MAX_DURATION =1 e ABORT_AFTER_WAIT =BLOCCANTI. Il blocco delle sessioni utente verrà interrotto dopo la durata massima del tempo di attesa.

Questo tipo di registrazione è molto utile per la risoluzione dei problemi e per scopi di controllo e sono felice di vederlo.