Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

So aktualisieren Sie SQL Server-Statistiken für große Tabellen

In meinem vorherigen Artikel habe ich kurz Datenbankstatistiken, ihre Bedeutung und warum Statistiken aktualisiert werden sollten, behandelt. Darüber hinaus habe ich einen schrittweisen Prozess zum Erstellen eines SQL Server-Wartungsplans zum Aktualisieren von Statistiken demonstriert. In diesem Artikel werden die folgenden Punkte erläutert:1. Wie man Statistiken mit einem T-SQL-Befehl aktualisiert. 2. Wie man die häufig aktualisierten Tabellen mit T-SQL identifiziert und auch die Statistiken von Tabellen mit häufig eingefügten/aktualisierten/gelöschten Daten aktualisiert.

Statistiken mit T-SQL aktualisieren

Sie können Statistiken mit dem T-SQL-Skript aktualisieren. Wenn Sie Statistiken mit T-SQL oder SQL Server Management Studio aktualisieren möchten, benötigen Sie ALTER database Berechtigung für die Datenbank. Sehen Sie sich das T-SQL-Codebeispiel an, um die Statistiken einer bestimmten Tabelle zu aktualisieren:

UPDATE STATISTICS <schema_name>.<table_name>.

Betrachten wir das Beispiel der Aktualisierung der Statistik der OrderLines Tabelle der WideWorldImporters Datenbank. Das folgende Skript erledigt dies.

UPDATE STATISTICS [Sales].[OrderLines]

Wenn Sie die Statistiken eines bestimmten Index aktualisieren möchten, können Sie das folgende Skript verwenden:

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

Falls Sie die Statistik der IX_Sales_OrderLines_Perf_20160301_02 aktualisieren möchten Index der OrderLines Tabelle können Sie das folgende Skript ausführen:

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

Sie können auch die Statistiken der gesamten Datenbank aktualisieren. Wenn Sie eine sehr kleine Datenbank mit wenigen Tabellen und wenig Daten haben, können Sie die Statistiken aller Tabellen innerhalb einer Datenbank aktualisieren. Siehe folgendes Skript:

USE wideworldimporters 
go 
EXEC Sp_updatestats

Aktualisierungsstatistik für Tabellen mit häufig eingefügten / aktualisierten / gelöschten Daten

Bei großen Datenbanken wird die Planung des Statistikjobs kompliziert, insbesondere wenn Sie nur wenige Stunden Zeit haben, um die Indexwartung durchzuführen, Statistiken zu aktualisieren und andere Wartungsaufgaben zu erledigen. Mit einer großen Datenbank meine ich eine Datenbank, die Tausende von Tabellen enthält, und jede Tabelle enthält Tausende von Zeilen. Zum Beispiel haben wir eine Datenbank namens X. Sie hat Hunderte von Tabellen, und jede Tabelle hat Millionen von Zeilen. Und nur wenige Tabellen werden häufig aktualisiert. Andere Tabellen werden selten geändert und es werden nur sehr wenige Transaktionen an ihnen durchgeführt. Wie ich bereits erwähnt habe, müssen Tabellenstatistiken auf dem neuesten Stand sein, um die Datenbankleistung auf dem neuesten Stand zu halten. Also erstellen wir einen SQL-Wartungsplan, um die Statistiken aller Tabellen in der X-Datenbank zu aktualisieren. Wenn der SQL-Server die Statistiken einer Tabelle aktualisiert, verwendet er eine beträchtliche Menge an Ressourcen, was zu Leistungsproblemen führen kann. Daher dauert es lange, die Statistiken von Hunderten von großen Tabellen zu aktualisieren, und während der Aktualisierung der Statistiken nimmt die Leistung der Datenbank erheblich ab. Unter solchen Umständen ist es immer ratsam, die Statistiken nur für die Tabellen zu aktualisieren, die häufig aktualisiert werden. Mit den folgenden dynamischen Verwaltungsansichten können Sie Änderungen des Datenvolumens oder der Anzahl der Zeilen im Laufe der Zeit verfolgen:1. sys.partitions gibt Auskunft über die Gesamtzahl der Zeilen in einer Tabelle. 2. sys.dm_db_partition_stats stellt Informationen über die Anzahl der Zeilen und Seiten pro Partition bereit. 3. sys.dm_db_index_physical_stats liefert Informationen über die Anzahl der Zeilen und Seiten sowie Informationen über die Indexfragmentierung und mehr. Die Angaben zum Datenvolumen sind wichtig, vervollständigen aber das Bild der Datenbankaktivität nicht. Beispielsweise kann eine Staging-Tabelle mit fast derselben Anzahl von Datensätzen jeden Tag aus der Tabelle gelöscht oder in eine Tabelle eingefügt werden. Aus diesem Grund würde eine Momentaufnahme der Anzahl der Zeilen darauf hindeuten, dass die Tabelle statisch ist. Möglicherweise haben die hinzugefügten und gelöschten Datensätze sehr unterschiedliche Werte, die die Datenverteilung stark verändern. In diesem Fall macht das automatische Aktualisieren von Statistiken in SQL Server Statistiken bedeutungslos. Daher ist es sehr nützlich, die Anzahl der Änderungen an einer Tabelle zu verfolgen. Dies kann auf folgende Weise geschehen:1. rowmodctr Spalte in sys.sysindexes 2. modified_count Spalte in sys.system_internals_partition_columns 3. modification_counter Spalte in sys.dm_db_stats_properties Wenn Sie also, wie ich bereits erklärt habe, nur wenig Zeit für die Datenbankwartung haben, ist es immer ratsam, die Statistiken nur für die Tabellen mit einer höheren Häufigkeit von Datenänderungen (Einfügen / Aktualisieren / Löschen) zu aktualisieren. Um dies effizient zu tun, habe ich ein Skript erstellt, das die Statistiken für die „aktiven“ Tabellen aktualisiert. Das Skript führt die folgenden Aufgaben aus:• Deklariert die erforderlichen Parameter. • Erstellt eine temporäre Tabelle mit dem Namen #tempstatistics zum Speichern des Tabellennamens, Schemanamens und Datenbanknamens • Erstellt eine weitere Tabelle mit dem Namen #tempdatabase um den Datenbanknamen zu speichern. Führen Sie zunächst das folgende Skript aus, um zwei Tabellen zu erstellen:

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

Schreiben Sie als Nächstes eine While-Schleife, um eine dynamische SQL-Abfrage zu erstellen, die alle Datenbanken durchläuft und eine Liste von Tabellen mit einem Änderungszähler größer als 200 in die #tempstatistics einfügt Tisch. Um Informationen über Datenänderungen zu erhalten, verwende ich sys.dm_db_stats_properties . Sehen Sie sich das folgende Codebeispiel an:

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

Erstellen Sie nun die zweite Schleife innerhalb der ersten Schleife. Es wird eine dynamische SQL-Abfrage generiert, die die Statistiken mit einem vollständigen Scan aktualisiert. Siehe das folgende Codebeispiel:

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

Sobald die Ausführung des Skripts abgeschlossen ist, werden alle temporären Tabellen gelöscht.

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

Das gesamte Skript wird wie folgt angezeigt:

--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

Sie können dieses Skript auch automatisieren, indem Sie einen SQL Server-Agent-Auftrag erstellen, der ihn zu einem geplanten Zeitpunkt ausführt. Eine Schritt-für-Schritt-Anleitung zur Automatisierung dieses Jobs finden Sie unten.

Erstellen eines SQL-Jobs

Lassen Sie uns zunächst einen SQL-Job erstellen, um den Prozess zu automatisieren. Öffnen Sie dazu SSMS, stellen Sie eine Verbindung zum gewünschten Server her und erweitern Sie den SQL Server Agent, klicken Sie mit der rechten Maustaste auf Jobs und wählen Sie Neuer Job aus . Im Neuen Job Geben Sie im Dialogfeld Name den gewünschten Namen ein Feld. Klicken Sie nun auf Schritte Menüoption im linken Bereich von Neuer Job Dialogfeld und klicken Sie dann auf Neu in den Schritten Fenster. Im Neuer Job-Schritt Geben Sie im sich öffnenden Dialogfeld den gewünschten Namen im Feld Schrittname ein Feld. Wählen Sie als Nächstes Transact-SQL-Skript (T-SQL) aus im Typ Dropdown-Feld. Wählen Sie dann DBATools aus in der Datenbank Dropdown-Feld und schreiben Sie die folgende Abfrage in das Befehlstextfeld:

EXEC Statistics_maintenance

Um den Zeitplan des Jobs zu konfigurieren, klicken Sie auf Zeitpläne Menüoption im Neuer Job Dialogbox. Der Neue Jobplan Dialogfeld öffnet sich. Im Namen Geben Sie im Feld den gewünschten Zeitplannamen ein. In unserem Beispiel soll dieser Job jede Nacht um 1 Uhr morgens ausgeführt werden, also im Occurs Drop-down-Feld in der Häufigkeit Wählen Sie im Abschnitt Täglich aus . Im Tritt einmalig um auf im Feld Tägliche Häufigkeit Abschnitt, geben Sie 01:00:00 ein. Klicken Sie auf OK um den Neuen Jobplan zu schließen Fenster und klicken Sie dann auf OK wieder im Neuen Job Dialogfeld, um es zu schließen. Lassen Sie uns nun diesen Job testen. Klicken Sie unter SQL Server Agent mit der rechten Maustaste auf Update_Statistics_Daily . Falls der Job erfolgreich ausgeführt wurde, sehen Sie das folgende Fenster.

Zusammenfassung

In diesem Artikel wurden die folgenden Themen behandelt:1. Wie man die Statistiken von Tabellen mit T-SQL-Skript aktualisiert. 2. Wie Sie Informationen über Änderungen des Datenvolumens und die Häufigkeit von Datenänderungen erhalten. 3. So erstellen Sie das Skript, das Statistiken für aktive Tabellen aktualisiert. 4. So erstellen Sie einen SQL Server Agent-Job, um das Skript zum geplanten Zeitpunkt auszuführen.