SQL Server 2014 CTP1 introduit des options d'attente de verrouillage de faible priorité à utiliser avec les opérations d'index en ligne et les commutateurs de partition.
Pour ceux qui utilisent la gestion d'index en ligne ou le partitionnement d'index et les opérations de changement de partition dans SQL Server 2012 Enterprise Edition, vous avez peut-être à un moment donné rencontré le blocage de votre opération DDL car ces opérations ont encore des exigences de verrouillage.
Pour illustrer, imaginez que j'exécute la reconstruction d'index en ligne à partition unique suivante dans SQL Server 2014 CTP1 :
ALTER INDEX [ClusteredIndex_on_ps_ShipDate] ON [dbo].[FactInternetSales] REBUILD PARTITION = (37) WITH (ONLINE= ON);
Et examinons les verrous acquis et libérés lors de cette opération de reconstruction à l'aide d'événements étendus et de la définition de session suivante (il s'agit d'une session sans cible et j'ai regardé les résultats via le volet « Regarder les données en direct » dans 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
La valeur 309576141 représente l'ID d'objet de la table FactInternetSales.
Ma reconstruction d'index en ligne d'une seule partition a pris 56 secondes et une fois terminée, j'ai vu l'activité d'acquisition et de libération de verrou suivante :
Activité de verrouillage pour la reconstruction en ligne d'une seule partition
Comme vous pouvez le voir dans la sortie, bien que la reconstruction soit une opération en ligne, elle implique l'acquisition de verrous dans différents modes tout au long du cycle de vie de l'opération. Idéalement, la durée du verrouillage est minimale (par exemple, l'horodatage est identique pour le premier SCH_S
serrure acquise et libérée). Mais même avec une quantité minimale de verrouillage, vous pouvez certainement rencontrer des problèmes de concurrence en fonction des transactions exécutées sur l'index en cours de reconstruction ou de basculement.
J'ai mentionné au début de cet article que Microsoft avait introduit des options d'attente de verrouillage de faible priorité pour les opérations en ligne et les opérations de changement de partition dans SQL Server 2014 CTP1. Au sujet des changements de partition, imaginez que j'exécute l'opération suivante :
ALTER TABLE [AdventureWorksDW2012].[dbo].[FactInternetSales] SWITCH PARTITION 37 TO [AdventureWorksDW2012].[dbo].[staging_FactInternetSales];
Pour voir les verrous acquis et libérés pour cette opération, j'ai modifié ma session d'événements étendus précédemment définie pour inclure les objets applicables (table source et cible). J'ai vu ce qui suit :
Activité de verrouillage pour une opération de changement de partition
L'opération de basculement vers une partition vide s'est produite en moins d'une seconde, mais nous voyons toujours que SCH_S
et SCH_M
des verrous étaient nécessaires pendant le cycle de vie de l'opération sur la source et la destination (309576141 étant FactInternetSales et 398624463 étant staging_FactInternetSales).
Encore une fois, alors que la durée du verrouillage peut être extrêmement brève lorsqu'il n'y a pas de transactions simultanées accédant aux objets en question, nous savons que ce n'est pas toujours possible et que nos opérations de reconstruction d'index en ligne et de changement de partition peuvent en effet être bloquées.
Donc avec cette réalité, SQL Server 2014 introduit le WAIT_AT_LOW_PRIORITY
argument qui peut être ajusté avec MAX_DURATION
et ABORT_AFTER_WAIT
options pour ALTER INDEX
et ALTER TABLE
commandes que nous pouvons utiliser pour les opérations d'indexation en ligne et de changement de partition.
Qu'est-ce que cela nous permet de faire ? Tout d'abord, parlons du comportement avant SQL Server 2014. Par exemple, imaginons que j'ai la transaction suivante ouverte et non validée :
BEGIN TRANSACTION; DELETE [dbo].[staging_FactInternetSales];
Si j'ai essayé d'effectuer un ALTER TABLE SWITCH
à la table staging_FactInternetSales en tant que destination dans une session séparée, je vais être bloqué et la demande va juste attendre. Spécifiquement pour cet exemple, j'attendrais avec un LCK_M_SCH_M
type d'attente. Une fois que j'ai annulé ou validé ma transaction, l'opération peut avancer et se terminer.
Maintenant, si j'utilise le WAIT_AT_LOW_PRIORITY
de SQL Server 2014 avec MAX_DURATION
et ABORT_AFTER_WAIT
, je peux tirer parti de quelques options différentes en fonction des exigences de mon application.
MAX_DURATION
me permet de spécifier le nombre de minutes d'attente de la reconstruction de l'index en ligne ou de l'opération de changement de partition. Si MAX_DURATION
est atteinte, nous pouvons définir ce qui se passe ensuite en fonction du paramètre de ABORT_AFTER_WAIT
, qui peut être une valeur de NONE
, SELF
ou BLOCKERS
:
NONE
signifie que l'opération d'indexation continuera à tenter l'opération.SELF
signifie que siMAX_DURATION
est atteint, l'opération (la reconstruction d'index en ligne ou le changement de partition) sera annulée.- Si
BLOCKERS
est utilisé, il tuera toutes les transactions qui bloquent la reconstruction de l'index en ligne ou l'opération de changement de partition (ce n'est pas une option, à mon avis, à utiliser à la légère).BLOCKERS
nécessite égalementALTER ANY CONNECTION
autorisation pour la requête émettant l'opération de reconstruction d'index en ligne ou de changement de partition.
Les exemples de code suivants illustrent différentes variantes de configuration.
Comportement par défaut avant 2014 (attendre indéfiniment)
- L'exécution de ce qui suit entraînera le comportement auquel nous sommes habitués avant SQL Server 2014, et il se peut que ce soit toujours ce que vous souhaiterez ou attendez dans certains scénarios :
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));
Attendez 1 minute et annulez l'opération DDL
- L'exemple suivant attend 1 minute s'il y a une transaction bloquante et obtiendra un "délai de demande de verrouillage dépassé" pour le
SWITCH
opération si la durée maximale est atteinte : 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));
Attendez 1 minute et tuez le(s) bloqueur(s)
- Cet exemple attend 1 minute s'il y a une transaction bloquante, puis tue les transactions bloquantes (source ou destination incluses), autorisant le
SWITCH
opération à terminer. 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));
Dans mon exemple de DELETE
à l'intérieur d'une transaction non validée, il n'y avait pas d'erreur dans ma fenêtre SQL Server Management Studio car je n'avais pas d'instruction en cours d'exécution, mais la tentative d'une autre instruction dans cette session a renvoyé le message d'erreur suivant (car ma session avait été tuée):
Une erreur de niveau transport s'est produite lors de l'envoi de la requête au serveur. (fournisseur :fournisseur de mémoire partagée, erreur :0 - aucun processus n'est à l'autre bout du canal.)
Tuez le(s) bloqueur(s) immédiatement (source ou destination pour SWITCH)
- Ce qui suit est un exemple de suppression immédiate du bloqueur - et dans mon exemple, le changement s'est produit en moins d'une seconde et, en effet, la session qui était le bloqueur a été supprimée :
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 dernier aspect positif que je voulais souligner…
Le journal des erreurs SQL Server fournit un audit par défaut de l'utilisation de l'attente de verrouillage de faible priorité, y compris des informations sur le ABORT_AFTER_WAIT
opération en ligne avec les informations de la victime :
Journal SQL Server (Actuel – 10/09/2013 12:03:00)
Source spid51
Message
Processus ID 57 a été tué par une instruction ABORT_AFTER_WAIT =BLOCKERS DDL sur database_id =5, object_id =309576141.
Et vous verrez également des entrées distinctes pour l'opération d'origine elle-même. Par exemple :
Une instruction ALTER TABLE SWITCH a été exécutée sur la base de données 'AdventureWorksDW2012', table 'staging_FactInternetSales' par le nom d'hôte 'WIN-4T7S36VMSD9', ID de processus hôte 1360 avec la table cible 'AdventureWorksDW2012.dbo.FactInternetSales' en utilisant les options WAIT_AT_LOW_PRIORITY avec MAX_DURATION =1 et ABORT_AFTER_WAIT =BLOQUEURS. Les sessions utilisateur bloquantes seront supprimées après la durée maximale du temps d'attente.Ce type de journalisation est très utile à des fins de dépannage et d'audit et je suis ravi de le voir.