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

Sådan opdateres SQL Server-statistikker for store tabeller

I min tidligere artikel har jeg kort dækket databasestatistik, dens betydning, og hvorfor statistikker bør opdateres. Desuden har jeg demonstreret en trin for trin-proces til at oprette en SQL Server-vedligeholdelsesplan for at opdatere statistik. I denne artikel vil følgende problemer blive forklaret:1. Sådan opdaterer du statistik ved hjælp af T-SQL Command. 2. Hvordan man identificerer de hyppigt opdaterede tabeller ved hjælp af T-SQL, og hvordan man også opdaterer statistikkerne for tabeller med hyppigt indsatte/opdaterede/slettede data.

Opdatering af statistik ved hjælp af T-SQL

Du kan opdatere statistik ved hjælp af T-SQL-scriptet. Hvis du vil opdatere statistik ved hjælp af T-SQL eller SQL Server Management Studio, skal du bruge ALTER database tilladelse til databasen. Se T-SQL-kodeeksemplet for at opdatere statistikkerne for en specifik tabel:

UPDATE STATISTICS <schema_name>.<table_name>.

Lad os overveje eksemplet med at opdatere statistikkerne for OrderLines tabel over WideWorldImporters database. Følgende script vil gøre det.

UPDATE STATISTICS [Sales].[OrderLines]

Hvis du vil opdatere statistikken for et bestemt indeks, kan du bruge følgende script:

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

Hvis du ønsker at opdatere statistikkerne for IX_Sales_OrderLines_Perf_20160301_02 indeks for OrderLines tabel, kan du udføre følgende script:

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

Du kan også opdatere statistikken for hele databasen. Hvis du har en meget lille database med få tabeller og en lille mængde data, så kan du opdatere statistikken for alle tabeller i en database. Se følgende script:

USE wideworldimporters 
go 
EXEC Sp_updatestats

Opdatering af statistik for tabeller med hyppigt indsatte/opdaterede/slettede data

På store databaser bliver planlægningen af ​​statistikjobbet kompliceret, især når du kun har et par timer til at udføre indeksvedligeholdelse, opdatere statistik og udføre andre vedligeholdelsesopgaver. Med en stor database mener jeg en database, der indeholder tusindvis af tabeller, og hver tabel indeholder tusindvis af rækker. For eksempel har vi en database ved navn X. Den har hundredvis af tabeller, og hver tabel har millioner af rækker. Og kun få tabeller bliver opdateret ofte. Andre tabeller ændres sjældent og har meget få transaktioner udført på dem. Som jeg nævnte før, for at holde databasens ydeevne op til mærket, skal tabelstatistikken være opdateret. Så vi laver en SQL-vedligeholdelsesplan for at opdatere statistikken for alle tabeller i X-databasen. Når SQL-serveren opdaterer statistikkerne for en tabel, bruger den en betydelig mængde ressourcer, hvilket kan føre til et ydeevneproblem. Så det tager lang tid at opdatere statistikker for hundredvis af store tabeller, og mens statistikken opdateres, reduceres databasens ydeevne betydeligt. Under sådanne omstændigheder er det altid tilrådeligt kun at opdatere statistikken for de tabeller, der opdateres hyppigt. Du kan holde styr på ændringer i datavolumen eller antal rækker over tid ved at bruge følgende dynamiske administrationsvisninger:1. sys.partitions giver information om det samlede antal rækker i en tabel. 2. sys.dm_db_partition_stats giver information om rækkeantal og sideantal pr. partition. 3. sys.dm_db_index_physical_stats giver information om antallet af rækker og sider, plus information om indeksfragmentering og mere. Detaljerne om datavolumen er vigtige, men de gør ikke billedet af databaseaktivitet komplet. For eksempel kan en iscenesættelsestabel, der har næsten det samme antal poster, slettes fra tabellen eller indsættes i en tabel hver dag. På grund af det, ville et øjebliksbillede af antallet af rækker tyde på, at tabellen er statisk. Det kan være muligt, at de tilføjede og slettede poster har meget forskellige værdier, som ændrer datafordelingen kraftigt. I dette tilfælde gør automatisk opdatering af statistik i SQL Server statistik meningsløs. Derfor er det meget nyttigt at spore antallet af ændringer til en tabel. Dette kan gøres på følgende måder:1. rowmodctr kolonne i sys.sysindexes 2. modified_count kolonne i sys.system_internals_partition_columns 3. modification_counter kolonne i sys.dm_db_stats_properties Således, som jeg forklarede tidligere, hvis du har begrænset tid til databasevedligeholdelse, er det altid tilrådeligt kun at opdatere statistikken for tabellerne med en højere frekvens af dataændringer (indsæt / opdater / slet). For at gøre det effektivt har jeg lavet et script, der opdaterer statistikkerne for de "aktive" tabeller. Scriptet udfører følgende opgaver:• Erklærer de nødvendige parametre • Opretter en midlertidig tabel med navnet #tempstatistics for at gemme tabelnavnet, skemanavnet og databasenavnet • Opretter en anden tabel ved navn #tempdatabase for at gemme databasenavnet. Først skal du udføre følgende script for at oprette to tabeller:

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

Skriv derefter en while-løkke for at skabe en dynamisk SQL-forespørgsel, der itererer gennem alle databaserne og indsætter en liste over tabeller, der har en modifikationstæller større end 200, i #tempstatistics bord. For at få oplysninger om dataændringer bruger jeg sys.dm_db_stats_properties . Studer følgende kodeeksempel:

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

Opret nu den anden løkke i den første løkke. Det vil generere en dynamisk SQL-forespørgsel, der opdaterer statistikken med fuld scanning. Se kodeeksemplet nedenfor:

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

Når scriptet er udført, vil det slette alle midlertidige tabeller.

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

Hele scriptet vises som følger:

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

Du kan også automatisere dette script ved at oprette et SQL Server Agent-job, som vil udføre det på et planlagt tidspunkt. En trinvis instruktion i automatisering af dette job er givet nedenfor.

Oprettelse af et SQL-job

Lad os først oprette et SQL-job for at automatisere processen. For at gøre det skal du åbne SSMS, oprette forbindelse til den ønskede server og udvide SQL Server Agent, højreklikke på Jobs og vælg Nyt job . I Nyt job dialogboksen, skriv det ønskede navn i Navn Mark. Klik nu på Trin menuindstillingen i venstre panel af Nyt job dialogboksen, og klik derefter på Ny i trinnene vindue. I Nyt job-trinet dialogboksen, der åbnes, angiv det ønskede navn i Trinnavnet Mark. Vælg derefter Transact-SQL-script (T-SQL) i Type drop-down boks. Vælg derefter DBATools i databasen rullemenuen og skriv følgende forespørgsel i kommandotekstboksen:

EXEC Statistics_maintenance

Klik på Schedules for at konfigurere tidsplanen for jobbet. menupunktet i Nyt job dialog boks. Ny jobplan dialogboksen åbnes. I Navn felt, skal du angive det ønskede skemanavn. I vores eksempel ønsker vi, at dette job skal udføres hver nat kl. 01.00, derfor i Occurs rullemenuen i Frekvens skal du vælge Dagligt . I Forekommer én gang kl feltet i Daglig frekvens sektion, indtast 01:00:00. Klik på OK for at lukke Nyt jobplan vindue, og klik derefter på OK igen i Nyt job dialogboksen for at lukke den. Lad os nu teste dette job. Højreklik på Update_Statistics_Daily under SQL Server Agent . Hvis jobbet er blevet udført med succes, vil du se følgende vindue.

Oversigt

I denne artikel er følgende emner blevet dækket:1. Sådan opdaterer du statistik over tabeller ved hjælp af T-SQL Script. 2. Hvordan man får information om ændringer i datamængde og hyppighed af dataændringer. 3. Sådan opretter du scriptet, der opdaterer statistik på aktive tabeller. 4. Sådan opretter du et SQL Server Agent Job for at udføre scriptet på det planlagte tidspunkt.


  1. Sådan vælger du Top N rækker pr. gruppe i MySQL

  2. Dynamisk opdateringserklæring med variable kolonnenavne

  3. Sådan opretter du en tabel i MySQL Workbench ved hjælp af GUI

  4. Rediger tabelrækker/registreringer i SQL Server Management Studio ( SSMS) - SQL Server vejledning / TSQL vejledning del 18