Database
 sql >> Base de données >  >> RDS >> Database

Le verrou DBCC_OBJECT_METADATA

Poursuivant ma série d'articles sur les verrous, cette fois, je vais discuter du verrou DBCC_OBJECT_METADATA et montrer comment il peut être un goulot d'étranglement majeur pour les vérifications de cohérence avant SQL Server 2016 dans certaines circonstances. Le problème affecte DBCC CHECKDB, DBCC CHECKTABLE et DBCC CHECKFILEGROUP, mais pour plus de clarté, je me contenterai de référencer DBCC CHECKDB pour le reste de cet article.

Vous vous demandez peut-être pourquoi j'écris sur un problème qui affecte les anciennes versions, mais il existe encore un grand nombre d'instances SQL Server 2014 et plus anciennes, c'est donc un sujet valable pour ma série.

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.

Qu'est-ce que le loquet DBCC_OBJECT_METADATA ?

Pour expliquer ce verrou, je dois expliquer un peu le fonctionnement de DBCC CHECKDB.

Parmi le grand nombre de vérifications de cohérence effectuées par DBCC CHECKDB figure une vérification de l'exactitude des index non clusterisés. Plus précisément, DBCC CHECKDB s'assure :

  1. Pour chaque enregistrement d'index non clusterisé dans chaque index non clusterisé, il existe exactement un enregistrement de données "correspondant" dans la table de base (soit un tas, soit un index clusterisé)
  2. Pour chaque enregistrement de données d'une table, il existe exactement un enregistrement d'index non cluster "correspondant" dans chaque index non cluster défini pour la table, en tenant compte des index filtrés

Sans entrer trop dans les détails de la façon dont cela est fait, pour chaque enregistrement de données dans une table, DBCC CHECKDB construit chaque enregistrement d'index non clusterisé qui devrait exister pour chaque index non clusterisé et s'assure que l'enregistrement d'index non clusterisé construit correspond exactement à l'enregistrement réel. enregistrement d'index non clusterisé. Si l'index non cluster contient une colonne calculée (soit dans le cadre de la clé d'index non cluster, soit en tant que colonne INCLUDE), DBCC CHECKDB doit déterminer la valeur de colonne calculée à utiliser lors de la construction des enregistrements d'index.

En plus des vérifications d'exactitude de l'index non clusterisé, s'il y a un persistant colonne calculée dans la définition d'une table, puis pour chaque enregistrement de données dans la table, DBCC CHECKDB doit vérifier que la valeur persistante est correcte, que cette colonne fasse partie d'un index non clusterisé ou non.

Alors, comment calcule-t-il les valeurs de colonne calculées ?

Le processeur de requêtes fournit un mécanisme de calcul des valeurs de colonne calculées, appelé « évaluateur d'expression ». DBCC CHECKDB appelle cette fonction, fournissant les informations de métadonnées appropriées et l'enregistrement de données, et l'évaluateur d'expression utilise la définition stockée de la colonne calculée dans les métadonnées et les valeurs de l'enregistrement de données et renvoie la valeur de la colonne calculée pour DBCC CHECKDB à utiliser . Le fonctionnement interne de l'évaluateur d'expression échappe au contrôle du code DBCC, mais pour pouvoir utiliser l'évaluateur d'expression, un verrou doit d'abord être acquis ; le verrou DBCC_OBJECT_METADATA.

Comment le loquet devient-il un goulot d'étranglement ?

Voici le problème :il n'y a qu'un seul mode acceptable dans lequel le verrou DBCC_OBJECT_METADATA peut être acquis avant d'utiliser l'évaluateur d'expression, et c'est le mode EX (exclusif). Et comme vous le saurez en lisant l'article d'introduction de la série, un seul fil à la fois peut maintenir le loquet en mode EX.

Rassembler toutes ces informations :lorsqu'une base de données contient des colonnes calculées persistantes ou des index non clusterisés contenant des colonnes calculées, l'évaluateur d'expression doit être utilisé. Si l'édition SQL Server est Enterprise, DBCC CHECKDB est capable d'utiliser le parallélisme et dispose donc de plusieurs threads effectuant les différentes vérifications. Et dès que vous avez plusieurs threads essayant d'acquérir un verrou en mode EX, ce verrou devient un goulot d'étranglement. L'ampleur d'un goulot d'étranglement dépend de la quantité d'utilisation de l'évaluateur d'expression. Ainsi, plus il y a de colonnes calculées persistantes ou d'index non clusterisés utilisant des colonnes calculées, et plus le nombre de lignes de table dans ces tables est grand, le plus le goulot d'étranglement devient le verrou DBCC _OBJECT_METADATA.

Mais rappelez-vous, ce goulot d'étranglement ne se produit que pour les versions de SQL Server antérieures à SQL Server 2016. Dans SQL Server 2016, Microsoft a décidé de "réparer" le goulot d'étranglement en désactivant les vérifications des index non clusterisés à l'aide de colonnes calculées par défaut et en ne les faisant que lorsque le WITH L'option EXTENDED_LOGICAL_CHECKS est utilisée.

Montrer le goulot d'étranglement

Vous pouvez facilement reproduire le goulot d'étranglement par vous-même en exécutant DBCC CHECKDB sur une base de données contenant des colonnes calculées persistantes ou des index non clusterisés avec des colonnes calculées, et la base de données AdventureWorks fournie par Microsoft en est un excellent exemple. Vous pouvez télécharger des sauvegardes d'AdventureWorks pour votre version de SQL Server à partir d'ici. J'ai effectué des tests en utilisant une base de données AdventureWorks2014 sur une instance SQL Server 2014 (sur un Dell R720 à 32 cœurs) et j'ai agrandi la base de données à quelques centaines de Go à l'aide des scripts de Jonathan.

Lorsque j'ai exécuté DBCC CHECKDB, avec le serveur MAXDOP défini sur 0, l'exécution a pris plus de 5 heures. Le type d'attente LATCH_EX représentait environ 30 % des attentes, chaque attente étant à peine inférieure à 1 milliseconde, et 99 % des attentes LATCH_EX concernaient le verrou DBCC_OBJECT_METADATA.

J'ai recherché des index non clusterisés contenant des colonnes calculées à l'aide du code suivant :

SELECT [s].[nom] AS [Schéma], [o].[nom] AS [Objet], [i].[nom] AS [Index], [c].[nom] AS [Colonne ], [ic].* FROM sys.columns [c] JOIN sys.index_columns [ic] ON [ic].[object_id] =[c].[object_id] AND [ic].[column_id] =[c]. [column_id] JOIN sys.indexes [i] ON [i].[object_id] =[ic].[object_id] AND [i].[index_id] =[ic].[index_id] JOIN sys.objects [o] ON [i].[object_id] =[o].[object_id] JOIN sys.schemas [s] ON [o].[schema_id] =[s].[schema_id] WHERE [c].[is_computed] =1; 

Ce code a trouvé six index non clusterisés dans la base de données AdventureWorks2014. J'ai désactivé les six index (en utilisant ALTER INDEX … DISABLE) et réexécuté DBCC CHECKDB et cela s'est terminé en 18 minutes environ. Ainsi, le goulot d'étranglement du verrou DBCC_OBJECT_METADATA a été un facteur majeur pour que DBCC CHECKDB s'exécute plus de 16 fois plus lentement !

Résumé

Malheureusement, la désactivation des index non clusterisés à l'aide de colonnes calculées (puis leur réactivation ultérieure à l'aide d'ALTER INDEX … REBUILD) est le * seul * moyen de supprimer le goulot d'étranglement de verrouillage DBCC_OBJECT_METADATA dans les versions antérieures à SQL Server 2016 tout en conservant toutes les autres fonctionnalités de DBCC CHECKDB. La désactivation des index non clusterisés n'est probablement pas quelque chose que vous voudrez faire dans un environnement de production, sauf si vous disposez d'une fenêtre de maintenance sans activité. Cela signifie que vous allez probablement uniquement désactiver ces index non clusterisés pour supprimer le goulot d'étranglement si vos vérifications de cohérence sont déchargées sur un autre serveur à l'aide de la méthode backup-copy-restore-CHECKDB.

Une autre façon de procéder consiste à utiliser l'option WITH PHYSICAL_ONLY lors de l'exécution de DBCC CHECKDB, mais vous manquez alors toutes les vérifications logiques approfondies, donc je ne suis pas un grand fan de recommander cela comme solution.