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

Comment mettre à jour les statistiques de SQL Server pour les grandes tables

Dans mon article précédent, j'ai brièvement couvert les statistiques des bases de données, leur importance et pourquoi les statistiques doivent être mises à jour. De plus, j'ai démontré un processus étape par étape pour créer un plan de maintenance SQL Server pour mettre à jour les statistiques. Dans cet article, les problèmes suivants seront expliqués :1. Comment mettre à jour les statistiques à l'aide de la commande T-SQL. 2. Comment identifier les tables fréquemment mises à jour à l'aide de T-SQL et également comment mettre à jour les statistiques des tables avec des données fréquemment insérées/mises à jour/supprimées.

Mise à jour des statistiques à l'aide de T-SQL

Vous pouvez mettre à jour les statistiques à l'aide du script T-SQL. Si vous souhaitez mettre à jour les statistiques à l'aide de T-SQL ou du studio de gestion SQL Server, vous avez besoin de la base de données ALTER autorisation sur la base de données. Voir l'exemple de code T-SQL pour mettre à jour les statistiques d'une table spécifique :

UPDATE STATISTICS <schema_name>.<table_name>.

Prenons l'exemple de la mise à jour des statistiques des OrderLines tableau des WideWorldImporters base de données. Le script suivant fera cela.

UPDATE STATISTICS [Sales].[OrderLines]

Si vous souhaitez mettre à jour les statistiques d'un index spécifique, vous pouvez utiliser le script suivant :

UPDATE STATISTICS <schema_name>.<table_name> <index_name>

Si vous souhaitez mettre à jour les statistiques du IX_Sales_OrderLines_Perf_20160301_02 index des Lignes de commande table, vous pouvez exécuter le script suivant :

UPDATE STATISTICS [Sales].[OrderLines] [IX_Sales_OrderLines_Perf_20160301_02]

Vous pouvez également mettre à jour les statistiques de toute la base de données. Si vous avez une très petite base de données avec peu de tables et peu de données, vous pouvez mettre à jour les statistiques de toutes les tables d'une base de données. Voir le script suivant :

USE wideworldimporters 
go 
EXEC Sp_updatestats

Mise à jour des statistiques pour les tableaux contenant des données fréquemment insérées/mises à jour/supprimées

Sur les bases de données volumineuses, la planification de la tâche de statistiques devient compliquée, en particulier lorsque vous ne disposez que de quelques heures pour effectuer la maintenance de l'index, mettre à jour les statistiques et effectuer d'autres tâches de maintenance. Par grande base de données, j'entends une base de données qui contient des milliers de tables et chaque table contient des milliers de lignes. Par exemple, nous avons une base de données nommée X. Elle contient des centaines de tables et chaque table contient des millions de lignes. Et seuls quelques tableaux sont mis à jour fréquemment. Les autres tables sont rarement modifiées et ont très peu de transactions effectuées sur elles. Comme je l'ai mentionné précédemment, pour maintenir les performances de la base de données à la hauteur, les statistiques des tables doivent être à jour. Nous créons donc un plan de maintenance SQL pour mettre à jour les statistiques de toutes les tables de la base de données X. Lorsque SQL Server met à jour les statistiques d'une table, il utilise une quantité importante de ressources, ce qui peut entraîner un problème de performances. Ainsi, la mise à jour des statistiques de centaines de grandes tables prend beaucoup de temps et, pendant la mise à jour des statistiques, les performances de la base de données diminuent considérablement. Dans de telles circonstances, il est toujours conseillé de mettre à jour les statistiques uniquement pour les tables fréquemment mises à jour. Vous pouvez suivre les modifications du volume de données ou du nombre de lignes au fil du temps en utilisant les vues de gestion dynamiques suivantes :1. sys.partitions fournit des informations sur le nombre total de lignes dans une table. 2. sys.dm_db_partition_stats fournit des informations sur le nombre de lignes et le nombre de pages, par partition. 3. sys.dm_db_index_physical_stats fournit des informations sur le nombre de lignes et de pages, ainsi que des informations sur la fragmentation des index, etc. Les détails sur le volume de données sont importants, mais ils ne donnent pas une image complète de l'activité de la base de données. Par exemple, une table intermédiaire qui contient presque le même nombre d'enregistrements peut être supprimée de la table ou insérée dans une table tous les jours. Pour cette raison, un instantané du nombre de lignes suggérerait que la table est statique. Il est possible que les enregistrements ajoutés et supprimés aient des valeurs très différentes qui modifient fortement la distribution des données. Dans ce cas, la mise à jour automatique des statistiques dans SQL Server rend les statistiques inutiles. Par conséquent, le suivi du nombre de modifications apportées à une table est très utile. Cela peut être fait des manières suivantes :1. rowmodctr colonne dans sys.sysindexes 2. modified_count colonne dans sys.system_internals_partition_columns 3. modification_counter colonne dans sys.dm_db_stats_properties Ainsi, comme je l'ai expliqué précédemment, si vous disposez d'un temps limité pour la maintenance de la base de données, il est toujours conseillé de mettre à jour les statistiques uniquement pour les tables avec une fréquence de changement de données plus élevée (insertion / mise à jour / suppression). Pour le faire efficacement, j'ai créé un script qui met à jour les statistiques des tables "actives". Le script effectue les tâches suivantes :• Déclare les paramètres requis • Crée une table temporaire nommée #tempstatistics pour stocker le nom de la table, le nom du schéma et le nom de la base de données • Crée une autre table nommée #tempdatabase pour stocker le nom de la base de données. Tout d'abord, exécutez le script suivant pour créer deux tables :

DECLARE @databasename VARCHAR(500) 
DECLARE @i INT=0 
DECLARE @DBCOunt INT 
DECLARE @SQLCOmmand NVARCHAR(max) 
DECLARE @StatsUpdateCOmmand NVARCHAR(max) 

CREATE TABLE #tempstatistics 
  ( 
     databasename VARCHAR(max), 
     tablename    VARCHAR(max), 
     schemaname   VARCHAR(max) 
  ) 

CREATE TABLE #tempdatabases 
  ( 
     databasename VARCHAR(max) 
  ) 

INSERT INTO #tempdatabases 
            (databasename) 
SELECT NAME 
FROM   sys.databases 
WHERE  database_id > 4 
ORDER  BY NAME

Ensuite, écrivez une boucle while pour créer une requête SQL dynamique qui parcourt toutes les bases de données et insère une liste de tables ayant un compteur de modifications supérieur à 200 dans #tempstatistics table. Pour obtenir des informations sur les modifications de données, j'utilise sys.dm_db_stats_properties . Étudiez l'exemple de code suivant :

SET @DBCOunt=(SELECT Count(*) 
                    FROM   #tempdatabases) 
      WHILE ( @i < @DBCOunt ) 
        BEGIN 
            DECLARE @DBName VARCHAR(max) 
            SET @DBName=(SELECT TOP 1 databasename 
                         FROM   #tempdatabases) 
            SET @SQLCOmmand= '     use [' + @DBName + '];     select 
distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter       FROM [' + @DBName+ '].sys.objects AS obj     inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id   INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id    CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like 
''sys%'')a' 
    INSERT INTO #tempstatistics 
                (databasename, 
                 tablename, 
                 schemaname) 
    EXEC Sp_executesql 
      @SQLCOmmand

Maintenant, créez la deuxième boucle dans la première boucle. Il générera une requête SQL dynamique qui met à jour les statistiques avec une analyse complète. Voir l'exemple de code ci-dessous :

DECLARE @j INT=0 
    DECLARE @StatCount INT 

    SET @StatCount =(SELECT Count(*) 
                     FROM   #tempstatistics) 

    WHILE @J < @StatCount 
      BEGIN 
          DECLARE @DatabaseName_Stats VARCHAR(max) 
          DECLARE @Table_Stats VARCHAR(max) 
          DECLARE @Schema_Stats VARCHAR(max) 
          DECLARE @StatUpdateCommand NVARCHAR(max) 

          SET @DatabaseName_Stats=(SELECT TOP 1 databasename 
                                   FROM   #tempstatistics) 
          SET @Table_Stats=(SELECT TOP 1 tablename 
                            FROM   #tempstatistics) 
          SET @Schema_Stats=(SELECT TOP 1 schemaname 
                             FROM   #tempstatistics) 
          SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats 
                                 + '].[' + @Schema_Stats + '].[' + @Table_Stats 
                                 + '] with fullscan' 
          EXEC Sp_executesql 
            @StatUpdateCommand 
          SET @[email protected] + 1 
          DELETE FROM #tempstatistics 
          WHERE  databasename = @DatabaseName_Stats 
                 AND tablename = @Table_Stats 
                 AND schemaname = @Schema_Stats 
      END 
    SET @[email protected] + 1 
    DELETE FROM #tempdatabases 
    WHERE  databasename = @DBName 
END

Une fois l'exécution du script terminée, il supprimera toutes les tables temporaires.

SELECT * 
    FROM   #tempstatistics 
    DROP TABLE #tempdatabases 
    DROP TABLE #tempstatistics

Le script entier apparaîtra comme suit :

--set count on     
CREATE PROCEDURE Statistics_maintenance 
AS 
  BEGIN 
      DECLARE @databasename VARCHAR(500) 
      DECLARE @i INT=0 
      DECLARE @DBCOunt INT 
      DECLARE @SQLCOmmand NVARCHAR(max) 
      DECLARE @StatsUpdateCOmmand NVARCHAR(max) 
      CREATE TABLE #tempstatistics 
        ( 
           databasename VARCHAR(max), 
           tablename    VARCHAR(max), 
           schemaname   VARCHAR(max) 
        ) 
      CREATE TABLE #tempdatabases 
        ( 
           databasename VARCHAR(max) 
        ) 
      INSERT INTO #tempdatabases 
                  (databasename) 
      SELECT NAME 
      FROM   sys.databases 
      WHERE  database_id > 4  
      ORDER  BY NAME 
      SET @DBCOunt=(SELECT Count(*) 
                    FROM   #tempdatabases) 
      WHILE ( @i < @DBCOunt ) 
        BEGIN 
            DECLARE @DBName VARCHAR(max) 
            SET @DBName=(SELECT TOP 1 databasename 
                         FROM   #tempdatabases) 
            SET @SQLCOmmand= '     use [' + @DBName + '];     select 
distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter       FROM [' + @DBName+ '].sys.objects AS obj     inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id   INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id    CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like 
''sys%'')a' 
    INSERT INTO #tempstatistics 
                (databasename, 
                 tablename, 
                 schemaname) 
    EXEC Sp_executesql 
      @SQLCOmmand 

    DECLARE @j INT=0 
    DECLARE @StatCount INT 

    SET @StatCount =(SELECT Count(*) 
                     FROM   #tempstatistics) 

    WHILE @J < @StatCount 
      BEGIN 
          DECLARE @DatabaseName_Stats VARCHAR(max) 
          DECLARE @Table_Stats VARCHAR(max) 
          DECLARE @Schema_Stats VARCHAR(max) 
          DECLARE @StatUpdateCommand NVARCHAR(max) 

          SET @DatabaseName_Stats=(SELECT TOP 1 databasename 
                                   FROM   #tempstatistics) 
          SET @Table_Stats=(SELECT TOP 1 tablename 
                            FROM   #tempstatistics) 
          SET @Schema_Stats=(SELECT TOP 1 schemaname 
                             FROM   #tempstatistics) 
          SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats 
                                 + '].[' + @Schema_Stats + '].[' + @Table_Stats 
                                 + '] with fullscan' 
          EXEC Sp_executesql 
            @StatUpdateCommand 
          SET @[email protected] + 1 
          DELETE FROM #tempstatistics 
          WHERE  databasename = @DatabaseName_Stats 
                 AND tablename = @Table_Stats 
                 AND schemaname = @Schema_Stats 
      END 
    SET @[email protected] + 1 
    DELETE FROM #tempdatabases 
    WHERE  databasename = @DBName 
END 
    SELECT * 
    FROM   #tempstatistics 
    DROP TABLE #tempdatabases 
    DROP TABLE #tempstatistics 
END

Vous pouvez également automatiser ce script en créant un travail de l'Agent SQL Server qui l'exécutera à une heure planifiée. Une instruction étape par étape d'automatisation de ce travail est donnée ci-dessous.

Créer une tâche SQL

Commençons par créer un Job SQL pour automatiser le processus. Pour ce faire, ouvrez SSMS, connectez-vous au serveur souhaité et développez SQL Server Agent, cliquez avec le bouton droit sur Jobs et sélectionnez Nouvelle tâche . Dans le Nouveau travail boîte de dialogue, saisissez le nom souhaité dans le champ Nom domaine. Maintenant, cliquez sur Étapes option de menu sur le panneau de gauche de la Nouvelle tâche boîte de dialogue, puis cliquez sur Nouveau dans les Étapes la fenêtre. Dans l'étape Nouvelle tâche boîte de dialogue qui s'ouvre, indiquez le nom souhaité dans le champ Nom de l'étape domaine. Ensuite, sélectionnez Script Transact-SQL (T-SQL) dans le Type boîte déroulante. Ensuite, sélectionnez DBATools dans la base de données liste déroulante et écrivez la requête suivante dans la zone de texte de la commande :

EXEC Statistics_maintenance

Pour configurer la planification de la tâche, cliquez sur Planifications option de menu dans Nouvelle tâche boite de dialogue. Le Nouveau calendrier des tâches boîte de dialogue s'ouvre. Dans le Nom champ, indiquez le nom de l'horaire souhaité. Dans notre exemple, nous voulons que ce travail soit exécuté tous les soirs à 1h du matin, donc dans le champ Occurs liste déroulante dans la Fréquence section, sélectionnez Quotidien . Dans le Se produit une fois à dans le champ Fréquence quotidienne section, entrez 01:00:00. Cliquez sur OK pour fermer le Nouveau calendrier de tâche fenêtre, puis cliquez sur OK à nouveau dans le Nouveau travail boîte de dialogue pour la fermer. Testons maintenant ce travail. Sous SQL Server Agent, cliquez avec le bouton droit sur Update_Statistics_Daily . Si le travail a été exécuté avec succès, vous verrez la fenêtre suivante.

Résumé

Dans cet article, les problèmes suivants ont été abordés :1. Comment mettre à jour les statistiques des tables à l'aide de T-SQL Script. 2. Comment obtenir des informations sur les changements de volume de données et la fréquence des changements de données. 3. Comment créer le script qui met à jour les statistiques sur les tables actives. 4. Comment créer une tâche de l'Agent SQL Server pour exécuter le script à l'heure planifiée.