Pour terminer ma courte série d'articles sur les verrous, cette fois, je vais discuter de quelques autres verrous dans SQL Server que vous pourriez voir de temps en temps mais qui ne méritent pas un article complet à eux seuls. Comme d'habitude, je vous recommande fortement de lire le premier article de la série avant celui-ci, afin que vous ayez toutes les connaissances générales sur les verrous.
Le loquet LOG_MANAGER
Le verrou LOG_MANAGER est utilisé pour la synchronisation lors de certaines opérations impliquant le journal des transactions, et il existe un verrou LOG_MANAGER par base de données (chaque base de données ayant son propre gestionnaire de journaux). Il ne peut être acquis qu'en mode exclusif et peut constituer un goulot d'étranglement lors de la croissance du fichier journal des transactions. Le scénario dans lequel il deviendra évident qu'il s'agit d'un problème est le suivant :
- Le fichier journal a un petit ensemble de croissance automatique
- Il existe de nombreuses connexions simultanées générant des enregistrements de journal des transactions
- Le fichier journal ne cesse de croître
Lorsque le fichier journal manque d'espace, il devra s'agrandir. Le premier thread à réaliser que plus d'espace de journal est requis acquiert le verrou LOG_MANAGER en mode EX et procède à la croissance du fichier journal. De nombreux autres threads continuent d'essayer de générer des enregistrements de journal et d'entrer dans la file d'attente du verrou LOG_MANAGER, afin de pouvoir développer le fichier journal. Lorsque le premier thread libère le verrou, le suivant l'obtient et se rend compte que le journal a déjà augmenté, alors supprimez-le et continuez. Ainsi de suite. Incidemment, ce modèle de goulot d'étranglement est appelé un convoi de verrouillage .
Vous pouvez en quelque sorte le considérer comme exactement le même goulot d'étranglement qu'avec le verrou FGCB_ADD_REMOVE dont j'ai parlé plus tôt dans la série, mais avec une croissance du fichier journal au lieu de la croissance du fichier de données. Cependant, avec le verrou FGCB_ADD_REMOVE, l'initialisation instantanée du fichier est généralement activée pour l'instance, de sorte que la croissance du fichier est très rapide, mais avec le verrou LOG_MANAGER, le journal *doit* être initialisé à zéro et le temps perdu dans la file d'attente du verrou est plus long. .
La solution à ce goulot d'étranglement comporte trois parties :
- Définissez correctement la croissance automatique du fichier journal, afin que le journal n'augmente pas fréquemment
- Dimensionnez le journal correctement pour la charge de travail, de sorte que le journal ne devrait pas grossir du tout
- Assurez-vous que le journal s'efface correctement, afin qu'il n'ait pas besoin de s'agrandir
Si tout cela est en place, vous ne devriez pas voir le verrou LOG_MANAGER être un goulot d'étranglement régulier, et j'en parle plus dans mon article ici.
Le loquet ACCESS_METHODS_DATASET_PARENT
Lors de l'accès à un tas ou à un index, il existe en interne un objet appelé HeapDataSetSession ou IndexDataSetSession, respectivement. Lorsqu'une analyse parallèle est effectuée, les threads effectuant le travail réel de l'analyse ont chacun un jeu de données "enfant" (une autre instance des deux objets que je viens de décrire), et le jeu de données principal, qui contrôle réellement l'analyse, s'appelle le "parent".
Lorsque l'un des threads de travail d'analyse a épuisé l'ensemble de lignes qu'il est censé analyser, il doit obtenir une nouvelle plage en accédant à l'ensemble de données parent, ce qui signifie acquérir le verrou ACCESS_METHODS_DATASET_PARENT en mode exclusif. Bien que cela puisse sembler être un goulot d'étranglement, ce n'en est pas vraiment un, et vous ne pouvez rien faire pour empêcher les threads effectuant une analyse parallèle d'afficher occasionnellement une attente LATCH_EX pour ce verrou.
La question que vous devriez vous poser est la suivante :cette requête doit-elle effectuer une analyse parallèle en premier lieu ? Il est tout à fait possible que quelque chose se soit passé pour forcer le plan de requête à inclure une analyse parallèle alors que ce n'est peut-être pas la manière la plus efficace d'exécuter la requête. Voici des exemples de choses qui pourraient faire passer un plan à une analyse parallèle :
- Statistiques obsolètes
- Un index non cluster manquant ou supprimé
- Nouveau code forçant une analyse en raison d'une conversion implicite :une incompatibilité de type de données entre une colonne et une variable/un paramètre, qui empêche l'utilisation d'un index non clusterisé
- Nouveau code forçant une analyse car l'arithmétique est effectuée sur une colonne de table au lieu d'une variable/paramètre, ce qui empêche à nouveau l'utilisation d'un index non clusterisé
- La croissance des données se produit et une analyse est vraiment le plan le plus efficace
Ou il se peut que cette requête nécessite une analyse, auquel cas les attentes LATCH_EX pour ACCESS_METHODS_DATASET_PARENT ne font qu'une partie de votre environnement.
Le verrou ACCESS_METHODS_HOBT_VIRTUAL_ROOT
Chaque instance de ce verrou protège une entrée dans les métadonnées du moteur de stockage pour un b-tree, en particulier l'ID de page de la page racine du b-tree (la page en haut du triangle que nous considérons généralement comme un index) . Je dis spécifiquement b-tree et non index , car un index peut avoir plusieurs partitions, chacune ayant un b-tree (essentiellement une partie de l'index global, mais avec des contraintes de clé de valeur faible et élevée).
Chaque fois qu'un thread doit traverser un b-tree, il doit commencer à la page racine et descendre jusqu'au niveau feuille. Pour lire les métadonnées contenant l'ID de page de la page racine, le thread doit acquérir le verrou ACCESS_METHODS_HOBT_VIRTUAL_ROOT en mode SH, pour s'assurer que l'ID de page n'est pas en train de changer. Lorsqu'un thread a besoin de changer l'ID de page de la page racine, il doit acquérir le verrou en mode EX.
Pourquoi la page racine d'un b-tree changerait-elle ? Au fur et à mesure que le nombre d'enregistrements d'index dans la page racine augmente, elle finira par se remplir et une division de page se produira. Lorsque cela se produit, la page racine actuelle et la page en laquelle elle se divise deviennent un nouveau niveau dans le b-tree, et une toute nouvelle page racine est créée, avec deux enregistrements d'index, pointant vers l'ancienne page racine et la page qu'elle contient. divisé en. Le nouvel ID de page racine doit être entré dans les métadonnées, de sorte que le verrou est acquis en mode EX. Cela se produira plusieurs fois rapidement, car un index sur une table vide commence à être rempli d'insertions, mais ce n'est pas quelque chose que vous verrez comme un problème de goulot d'étranglement permanent des performances.
Résumé
Comme je suis sûr que vous l'avez compris dans cette série, comprendre les verrous et les goulots d'étranglement des verrous implique d'en savoir un peu plus sur ce qui se passe à l'intérieur du moteur de stockage que pour l'analyse générale des statistiques d'attente.
Je conseille généralement aux gens * de ne pas * commencer le dépannage des performances en consultant les statistiques de verrouillage (via sys.dm_os_latch_stats ) mais au lieu de toujours commencer par les statistiques d'attente (voir mon article ici) et ne plonger dans les verrous que si LATCH_EX ou LATCH_SH sont l'une des meilleures attentes sur l'instance SQL Server.
Si vous avez des questions sur les verrous, n'hésitez pas à m'écrire.