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

Prise en charge améliorée des reconstructions de statistiques parallèles

L'un des meilleurs moyens d'en savoir plus sur les bogues de SQL Server consiste à lire les notes de publication des mises à jour cumulatives et des Service Packs lorsqu'ils sortent. Cependant, c'est aussi parfois un excellent moyen d'en savoir plus sur les améliorations apportées à SQL Server.

Mise à jour cumulative 6 pour SQL Server 2014 Service Pack 1 introduit un nouvel indicateur de trace, 7471, qui modifie le comportement de verrouillage des tâches UPDATE STATISTICS dans SQL Server (voir KB #3156157). Dans cet article, nous examinerons la différence de comportement de verrouillage et où cet indicateur de trace pourrait être utile.

Pour configurer un environnement de démonstration approprié pour cet article, j'ai utilisé la base de données AdventureWorks2014 et créé une version agrandie de la table SalesOrderDetail basée sur le script disponible sur mon blog. La table SalesOrderDetailEnlarged a été agrandie à 2 Go afin que les opérations UPDATE STATISTICS WITH FULLSCAN puissent être exécutées simultanément sur différentes statistiques de la table. J'ai ensuite utilisé sp_whoisactive pour examiner les verrous détenus par les deux sessions.

Comportement sans TF 7471

Le comportement par défaut de SQL Server requiert un verrou exclusif (X) sur la ressource OBJECT.UPDSTATS pour la table chaque fois qu'une commande UPDATE STATISTICS est exécutée sur une table. Vous pouvez le voir dans la sortie sp_whoisactive pour deux exécutions simultanées de UPDATE STATISTICS WITH FULLSCAN sur la table Sales.SalesOrderDetailEnlarged, en utilisant des noms d'index différents pour les statistiques à mettre à jour. Cela entraîne le blocage de la deuxième exécution de UPDATE STATISTICS jusqu'à la fin de la première exécution.

METTRE À JOUR LES STATISTIQUES [Ventes].[SalesOrderDetailEnlarged] ([PK_SalesOrderDetailEnlarged_SalesOrderID_SalesOrderDetailID]) AVEC FULLSCAN ;
                                                
METTRE À JOUR LES STATISTIQUES [Ventes].[SalesOrderDetailEnlarged] ([IX_SalesOrderDetailEnlarged_ProductID]) AVEC FULLSCAN ;
                                        

La granularité de la ressource de verrouillage étant sur OBJECT.UPDSTATS empêche les mises à jour simultanées de plusieurs statistiques sur la même table. Les améliorations matérielles de ces dernières années ont vraiment changé les goulots d'étranglement potentiels communs aux implémentations de SQL Server, et tout comme des modifications ont été apportées à DBCC CHECKDB pour le rendre plus rapide, en modifiant le comportement de verrouillage de UPDATE STATISTICS pour permettre des mises à jour simultanées des statistiques sur le même table peut réduire considérablement les fenêtres de maintenance pour les VLDB, en particulier lorsque la capacité du processeur et du sous-système d'E/S est suffisante pour permettre des mises à jour simultanées sans affecter l'expérience de l'utilisateur final.

Comportement avec TF 7471

Le comportement de verrouillage avec l'indicateur de trace 7471 activé passe de l'exigence d'un verrou exclusif (X) sur la ressource OBJECT.UPDSTATS à l'exigence d'un verrou de mise à jour (U) sur la ressource METADATA.STATS pour la statistique spécifique qui est mise à jour, ce qui permet des exécutions simultanées de UPDATE STATISTICS sur la même table. La sortie de sp_whoisactive pour les mêmes commandes UPDATE STATISTICS WITH FULLCAN avec l'indicateur de trace activé est illustrée ci-dessous :

METTRE À JOUR LES STATISTIQUES [Ventes].[SalesOrderDetailEnlarged] ([PK_SalesOrderDetailEnlarged_SalesOrderID_SalesOrderDetailID]) AVEC FULLSCAN ;
                                        
METTRE À JOUR LES STATISTIQUES [Ventes].[SalesOrderDetailEnlarged] ([IX_SalesOrderDetailEnlarged_ProductID]) AVEC FULLSCAN ;
                                                     

Pour les VLDB, qui deviennent de plus en plus courantes, cela peut faire une grande différence dans le temps nécessaire pour effectuer les mises à jour des statistiques sur un serveur.

J'ai récemment blogué sur une solution de maintenance parallèle pour SQL Server utilisant Service Broker et les scripts de maintenance d'Ola Hallengren comme moyen d'optimiser les tâches de maintenance nocturnes et de réduire le temps nécessaire pour reconstruire les index et mettre à jour les statistiques sur les serveurs qui ont beaucoup de CPU et de capacité d'E/S disponible. Dans le cadre de cette solution, j'ai forcé un ordre de mise en file d'attente des tâches vers Service Broker pour essayer d'éviter d'avoir des exécutions simultanées sur la même table pour les tâches de reconstruction/réorganisation d'index et UPDATE STATISTICS. Le but était de garder les travailleurs aussi occupés que possible jusqu'à la fin des tâches de maintenance, où les choses se sérialiseraient dans l'exécution en fonction du blocage des tâches simultanées.

J'ai apporté quelques modifications au traitement dans cet article pour tester uniquement les effets de cet indicateur de trace avec des mises à jour de statistiques simultanées uniquement, et les résultats sont ci-dessous.

Tester les performances de la mise à jour des statistiques simultanées

Pour tester les performances de la mise à jour des statistiques uniquement en parallèle à l'aide de la configuration de Service Broker, j'ai commencé par créer une statistique de colonne sur chaque colonne de la base de données AdventureWorks2014 à l'aide du script suivant pour générer les commandes DDL à exécuter.

UTILISEZ [AdventureWorks2014]GO SELECT *, 'DROP STATISTICS ' + QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME) + '.' + QUOTENAME(c.TABLE_NAME + '_' + c.COLUMN_NAME) + ';GOCREATE STATISTICS ' +QUOTENAME(c.TABLE_NAME + '_' + c.COLUMN_NAME) + ' ON ' + QUOTENAME(c.TABLE_SCHEMA) + '. ' + QUOTENAME(c.TABLE_NAME) + ' (' +QUOTENAME(c.COLUMN_NAME) + ');' + 'GO' FROM INFORMATION_SCHEMA.COLUMNS AS cINNER JOIN INFORMATION_SCHEMA.TABLES AS t ON c.TABLE_CATALOG =t.TABLE_CATALOG AND c.TABLE_SCHEMA =t.TABLE_SCHEMA AND c.TABLE_NAME =t.TABLE_NAMEWHERE t.TABLE_TYPE ='BASE TABLE' AND c .DATA_TYPE <> N'xml';

Ce n'est pas quelque chose que vous voudriez généralement faire, mais cela me donne beaucoup de statistiques pour tester en parallèle l'impact de l'indicateur de trace sur la mise à jour simultanée des statistiques. Au lieu de randomiser l'ordre dans lequel je mets les tâches en file d'attente dans Service Broker, je place simplement les tâches en file d'attente telles qu'elles existent dans la table CommandLog en fonction de l'ID de la table, en incrémentant simplement l'ID d'un jusqu'à ce que toutes les commandes aient été mises en file d'attente. pour le traitement.

USE [maître] ; -- Effacer le journal des commandes TRUNCATE TABLE [master].[dbo].[CommandLog] ; DECLARE @MaxID INT;SELECT @MaxID =MAX(ID) FROM master.dbo.CommandLog; SELECT @MaxID =ISNULL(@MaxID, 1) ---- Charger de nouvelles tâches dans la commande LogEXEC master.dbo.IndexOptimize @Databases =N'AdventureWorks2014', @FragmentationLow =NULL, @FragmentationMedium =NULL, @FragmentationHigh =NULL, @UpdateStatistics ='ALL', @StatisticsSample =100, @LogToTable ='Y', @Execute ='N' ; DECLARE @NewMaxID INTSELECT @NewMaxID =MAX(ID) FROM master.dbo.CommandLog ; UTILISER msdb ; DECLARE @CurrentID INT =@MaxIDWHILE (@CurrentID <=@NewMaxID)BEGIN -- Commencer une conversation et envoyer un message de demande DECLARE @conversation_handle UNIQUEIDENTIFIER; DÉCLARER @message_body XML ; COMMENCER LA TRANSACTION ; COMMENCEZ LE DIALOGUE @conversation_handle DU SERVICE [OlaHallengrenMaintenanceTaskService] AU SERVICE N'OlaHallengrenMaintenanceTaskService' ON CONTRACT [OlaHallengrenMaintenanceTaskContract] WITH ENCRYPTION =OFF ; SELECT @message_body =N''+CAST(@CurrentID AS NVARCHAR)+N'' ; ENVOYER SUR CONVERSATION @conversation_handle TYPE DE MESSAGE [OlaHallengrenMaintenanceTaskMessage] (@message_body); ENGAGER LA TRANSACTION ; SET @CurrentID =@CurrentID + 1;END WHILE EXISTS (SELECT 1 FROM OlaHallengrenMaintenanceTaskQueue WITH(NOLOCK))BEGIN WAITFOR DELAY '00:00:01.000'END WAITFOR DELAY '00:00:06.000' SELECT DATEDIFF(ms, MIN(StartTime ), MAX(EndTime)) FROM master.dbo.CommandLog;GO 10

Ensuite, j'ai attendu que toutes les tâches soient terminées, mesuré le delta de l'heure de début et de l'heure de fin des exécutions de tâches, et pris la moyenne de dix tests pour déterminer les améliorations uniquement pour la mise à jour des statistiques en utilisant simultanément l'échantillonnage par défaut et les mises à jour d'analyse complète.

Les résultats des tests montrent que même avec le blocage qui se produit sous le comportement par défaut sans l'indicateur de trace, les mises à jour échantillonnées des statistiques s'exécutent 6 % plus rapidement et les mises à jour d'analyse complètes s'exécutent 16 % plus rapidement avec cinq threads traitant les tâches mises en file d'attente vers Service Broker. Avec l'indicateur de trace 7471 activé, les mêmes mises à jour échantillonnées de statistiques s'exécutent 38 % plus rapidement et les mises à jour d'analyse complètes s'exécutent 45 % plus rapidement avec cinq threads traitant les tâches mises en file d'attente pour Service Broker.

Défis potentiels avec TF 7471

Aussi convaincants que soient les résultats des tests, rien dans ce monde n'est gratuit et lors de mes premiers tests, j'ai rencontré des problèmes avec la taille de la machine virtuelle que j'utilisais sur mon ordinateur portable, ce qui a créé des problèmes de charge de travail.

À l'origine, je testais la maintenance parallèle à l'aide d'une machine virtuelle 4vCPU avec 4 Go de RAM que j'ai configurée spécifiquement à cet effet. Lorsque j'ai commencé à augmenter le nombre de MAX_QUEUE_READERS pour la procédure d'activation dans Service Broker, j'ai commencé à rencontrer des problèmes avec les attentes RESOURCE_SEMAPHORE lorsque l'indicateur de trace était activé, permettant des mises à jour parallèles des statistiques sur les tables agrandies de ma base de données AdventureWorks2014 en raison des exigences d'allocation de mémoire. pour chacune des commandes UPDATE STATISTICS en cours d'exécution. Cela a été atténué en changeant la configuration de la machine virtuelle en 16 Go de RAM, mais c'est quelque chose à surveiller et à surveiller lors de l'exécution de tâches parallèles sur des tables plus grandes, pour inclure la maintenance de l'index, car la privation d'allocation de mémoire affectera également les demandes des utilisateurs finaux qui peuvent essayer d'exécuter et ont également besoin d'une allocation de mémoire plus importante.

L'équipe produit a également blogué sur cet indicateur de trace et dans son message, elle avertit que des scénarios de blocage peuvent se produire lors de la mise à jour simultanée des statistiques pendant la création de statistiques. Ce n'est pas quelque chose que j'ai encore rencontré lors de mes tests, mais c'est certainement quelque chose dont il faut être conscient (Kendra Little met également en garde à ce sujet). En conséquence, leur recommandation est que cet indicateur de trace ne soit activé que pendant l'exécution de la tâche de maintenance parallèle, puis qu'il soit désactivé pendant les périodes de charge de travail normales.

Amusez-vous !