Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come aggiornare le statistiche di SQL Server per Big Table

Nel mio precedente articolo, ho trattato brevemente le statistiche del database, la sua importanza e il motivo per cui le statistiche dovrebbero essere aggiornate. Inoltre, ho dimostrato un processo passo dopo passo per creare un piano di manutenzione di SQL Server per aggiornare le statistiche. In questo articolo verranno spiegati i seguenti problemi:1. Come aggiornare le statistiche utilizzando il comando T-SQL. 2. Come identificare le tabelle aggiornate di frequente utilizzando T-SQL e anche come aggiornare le statistiche delle tabelle con dati inseriti/aggiornati/eliminati frequentemente.

Aggiornamento delle statistiche tramite T-SQL

È possibile aggiornare le statistiche utilizzando lo script T-SQL. Se desideri aggiornare le statistiche utilizzando T-SQL o SQL Server Management Studio, hai bisogno del database ALTER autorizzazione sul database. Vedere l'esempio di codice T-SQL per aggiornare le statistiche di una tabella specifica:

UPDATE STATISTICS <schema_name>.<table_name>.

Consideriamo l'esempio di aggiornamento delle statistiche delle OrderLines tabella di WideWorldImporters Banca dati. Il seguente script lo farà.

UPDATE STATISTICS [Sales].[OrderLines]

Se vuoi aggiornare le statistiche di un indice specifico, puoi utilizzare il seguente script:

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

Nel caso desideri aggiornare le statistiche delle IX_Sales_OrderLines_Perf_20160301_02 indice delle Righe d'ordine tabella, è possibile eseguire il seguente script:

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

Puoi anche aggiornare le statistiche dell'intero database. Se si dispone di un database molto piccolo con poche tabelle e poca quantità di dati, è possibile aggiornare le statistiche di tutte le tabelle all'interno di un database. Vedi il seguente script:

USE wideworldimporters 
go 
EXEC Sp_updatestats

Aggiornamento delle statistiche per le tabelle con dati inseriti/aggiornati/eliminati di frequente

Su database di grandi dimensioni, la pianificazione del lavoro delle statistiche diventa complicata, soprattutto quando hai solo poche ore per eseguire la manutenzione dell'indice, aggiornare le statistiche ed eseguire altre attività di manutenzione. Per database di grandi dimensioni intendo un database che contiene migliaia di tabelle e ogni tabella contiene migliaia di righe. Ad esempio, abbiamo un database chiamato X. Ha centinaia di tabelle e ogni tabella ha milioni di righe. E solo alcune tabelle vengono aggiornate frequentemente. Altre tabelle vengono modificate raramente e su di esse vengono eseguite pochissime transazioni. Come accennato in precedenza, per mantenere le prestazioni del database all'altezza, le statistiche delle tabelle devono essere aggiornate. Quindi creiamo un piano di manutenzione SQL per aggiornare le statistiche di tutte le tabelle all'interno del database X. Quando SQL Server aggiorna le statistiche di una tabella, utilizza una quantità significativa di risorse che può causare problemi di prestazioni. Pertanto, l'aggiornamento delle statistiche di centinaia di tabelle di grandi dimensioni richiede molto tempo e mentre le statistiche vengono aggiornate, le prestazioni del database si riducono notevolmente. In tali circostanze è sempre consigliabile aggiornare le statistiche solo per le tabelle che vengono aggiornate frequentemente. Puoi tenere traccia delle modifiche al volume di dati o al numero di righe nel tempo utilizzando le seguenti viste a gestione dinamica:1. sys.partitions fornisce informazioni sul numero totale di righe in una tabella. 2. sys.dm_db_partition_stats fornisce informazioni sui conteggi delle righe e delle pagine, per partizione. 3. sys.dm_db_index_physical_stats fornisce informazioni sul numero di righe e pagine, oltre a informazioni sulla frammentazione dell'indice e altro ancora. I dettagli sul volume dei dati sono importanti, ma non completano il quadro dell'attività del database. Ad esempio, una tabella di staging con quasi lo stesso numero di record può essere eliminata dalla tabella o inserita in una tabella ogni giorno. Per questo motivo, un'istantanea del numero di righe suggerisce che la tabella è statica. Potrebbe essere possibile che i record aggiunti ed eliminati abbiano valori molto diversi che modificano notevolmente la distribuzione dei dati. In questo caso, l'aggiornamento automatico delle statistiche in SQL Server rende le statistiche prive di significato. Pertanto, il monitoraggio del numero di modifiche a una tabella è molto utile. Questo può essere fatto nei seguenti modi:1. rowmodctr colonna in sys.sysindexes 2. conteggio_modificato colonna in sys.system_internals_partition_columns 3. contatore_modifica column in sys.dm_db_stats_properties Quindi, come ho spiegato in precedenza, se si dispone di un tempo limitato per la manutenzione del database, è sempre consigliabile aggiornare le statistiche solo per le tabelle con una maggiore frequenza di modifica dei dati (inserire/aggiornare/cancellare). Per farlo in modo efficiente, ho creato uno script che aggiorna le statistiche per le tabelle "attive". Lo script esegue le seguenti attività:• Dichiara i parametri richiesti • Crea una tabella temporanea denominata #tempstatistics per memorizzare il nome della tabella, il nome dello schema e il nome del database • Crea un'altra tabella denominata #tempdatabase per memorizzare il nome del database. Innanzitutto, esegui il seguente script per creare due tabelle:

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

Quindi, scrivi un ciclo while per creare una query SQL dinamica che esegua un'iterazione in tutti i database e inserisca un elenco di tabelle con un contatore di modifiche maggiore di 200 in #tempstatistics tavolo. Per ottenere informazioni sulle modifiche ai dati, utilizzo sys.dm_db_stats_properties . Studia il seguente esempio di codice:

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

Ora, crea il secondo ciclo all'interno del primo ciclo. Genererà una query SQL dinamica che aggiorna le statistiche con la scansione completa. Vedi l'esempio di codice qui sotto:

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

Una volta completata l'esecuzione dello script, verranno eliminate tutte le tabelle temporanee.

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

L'intero script apparirà come segue:

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

Puoi anche automatizzare questo script creando un processo di SQL Server Agent che lo eseguirà a un'ora pianificata. Di seguito viene fornita un'istruzione passo passo per automatizzare questo lavoro.

Creazione di un processo SQL

Innanzitutto, creiamo un processo SQL per automatizzare il processo. Per farlo, apri SSMS, connettiti al server desiderato ed espandi SQL Server Agent, fai clic con il pulsante destro del mouse su Lavori e seleziona Nuovo lavoro . Nel Nuovo lavoro finestra di dialogo, digitare il nome desiderato in Nome campo. Ora, fai clic su Passaggi opzione di menu nel pannello di sinistra di Nuovo lavoro finestra di dialogo, quindi fai clic su Nuovo nei Passaggi finestra. Nel nuovo passaggio di lavoro finestra di dialogo, che si apre, fornire il nome desiderato nel Nome del passaggio campo. Quindi, seleziona Script Transact-SQL (T-SQL) nel Tipo casella a discesa. Quindi, seleziona DBATools nel Banca dati casella a discesa e scrivi la seguente query nella casella di testo del comando:

EXEC Statistics_maintenance

Per configurare la pianificazione del lavoro, fare clic su Programmi opzione di menu in Nuovo lavoro la finestra di dialogo. Il nuovo programma di lavoro si apre la finestra di dialogo. Nel Nome campo, fornire il nome della pianificazione desiderata. Nel nostro esempio, vogliamo che questo lavoro venga eseguito ogni notte all'una di notte, quindi in Si verifica casella a discesa nella Frequenza sezione, seleziona Giornaliero . In Si verifica una volta a campo nella Frequenza giornaliera sezione, inserire 01:00:00. Fare clic su OK per chiudere il Nuovo programma di lavoro finestra e quindi fare clic su OK di nuovo nel Nuovo lavoro finestra di dialogo per chiuderla. Ora proviamo questo lavoro. In SQL Server Agent, fare clic con il pulsante destro del mouse su Aggiorna statistiche_giornaliere . Nel caso in cui il lavoro sia stato eseguito correttamente, verrà visualizzata la seguente finestra.

Riepilogo

In questo articolo sono stati trattati i seguenti problemi:1. Come aggiornare le statistiche delle tabelle che utilizzano T-SQL Script. 2. Come ottenere informazioni sulle modifiche al volume dei dati e alla frequenza delle modifiche ai dati. 3. Come creare lo script che aggiorna le statistiche sulle tabelle attive. 4. Come creare un processo di SQL Server Agent per eseguire lo script all'ora pianificata.