sql >> Databáze >  >> RDS >> Sqlserver

Jak aktualizovat statistiky serveru SQL pro velké tabulky

Ve svém předchozím článku jsem stručně popsal databázové statistiky, jejich důležitost a proč by se měly statistiky aktualizovat. Kromě toho jsem předvedl krok za krokem proces vytvoření plánu údržby serveru SQL Server pro aktualizaci statistik. V tomto článku budou vysvětleny následující problémy:1. Jak aktualizovat statistiky pomocí příkazu T-SQL. 2. Jak identifikovat často aktualizované tabulky pomocí T-SQL a také jak aktualizovat statistiku tabulek s často vkládanými/aktualizovanými/vymazávanými daty.

Aktualizace statistik pomocí T-SQL

Statistiky můžete aktualizovat pomocí skriptu T-SQL. Pokud chcete aktualizovat statistiky pomocí T-SQL nebo SQL Server Management Studio, potřebujete ALTER databázi oprávnění k databázi. Chcete-li aktualizovat statistiku konkrétní tabulky, podívejte se na příklad kódu T-SQL:

UPDATE STATISTICS <schema_name>.<table_name>.

Podívejme se na příklad aktualizace statistik OrderLines tabulky WideWorldImporters databáze. Následující skript to udělá.

UPDATE STATISTICS [Sales].[OrderLines]

Pokud chcete aktualizovat statistiky konkrétního indexu, můžete použít následující skript:

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

V případě, že chcete aktualizovat statistiky IX_Sales_OrderLines_Perf_20160301_02 indexu OrderLines tabulky, můžete spustit následující skript:

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

Můžete také aktualizovat statistiky celé databáze. Pokud máte velmi malou databázi s několika tabulkami a malým množstvím dat, můžete aktualizovat statistiky všech tabulek v databázi. Viz následující skript:

USE wideworldimporters 
go 
EXEC Sp_updatestats

Aktualizace statistik pro tabulky s často vkládanými / aktualizovanými / mazanými daty

U velkých databází se plánování úlohy statistiky komplikuje, zvláště když máte jen několik hodin na provedení údržby indexu, aktualizaci statistik a plnění dalších úkolů údržby. Velkou databází myslím databázi, která obsahuje tisíce tabulek a každá tabulka obsahuje tisíce řádků. Máme například databázi s názvem X. Obsahuje stovky tabulek a každá tabulka má miliony řádků. A jen několik tabulek je často aktualizováno. Jiné tabulky se mění jen zřídka a je na nich provedeno velmi málo transakcí. Jak jsem již zmínil, pro udržení výkonu databáze na úrovni musí být statistika tabulek aktuální. Vytvoříme tedy plán údržby SQL pro aktualizaci statistik všech tabulek v databázi X. Když SQL server aktualizuje statistiku tabulky, využívá značné množství zdrojů, což může vést k problémům s výkonem. Aktualizace statistik stovek velkých tabulek tedy trvá dlouho a zatímco se statistiky aktualizují, výkon databáze se výrazně snižuje. Za takových okolností je vždy vhodné aktualizovat statistiky pouze pro často aktualizované tabulky. Změny objemu dat nebo počtu řádků v průběhu času můžete sledovat pomocí následujících dynamických zobrazení správy:1. sys.partitions poskytuje informace o celkovém počtu řádků v tabulce. 2. sys.dm_db_partition_stats poskytuje informace o počtu řádků a počtech stránek na oddíl. 3. sys.dm_db_index_physical_stats poskytuje informace o počtu řádků a stránek plus informace o fragmentaci indexu a další. Podrobnosti o objemu dat jsou důležité, ale neutvářejí obraz o činnosti databáze úplný. Například pracovní tabulku, která má téměř stejný počet záznamů, lze z tabulky odstranit nebo vložit do tabulky každý den. Vzhledem k tomu by snímek počtu řádků naznačoval, že tabulka je statická. Je možné, že přidané a odstraněné záznamy mají velmi odlišné hodnoty, které výrazně mění distribuci dat. V tomto případě automatická aktualizace statistik v SQL Server dělá statistiky bezvýznamné. Proto je sledování počtu úprav v tabulce velmi užitečné. To lze provést následujícími způsoby:1. rowmodctr sloupec v sys.sysindexes 2. modified_count sloupec v sys.system_internals_partition_columns 3. počítadlo_změn sloupec v sys.dm_db_stats_properties Jak jsem již vysvětlil dříve, pokud máte omezený čas na údržbu databáze, je vždy vhodné aktualizovat statistiky pouze pro tabulky s vyšší frekvencí změn dat (vkládání / aktualizace / mazání). Abych toho dosáhl efektivně, vytvořil jsem skript, který aktualizuje statistiky pro „aktivní“ tabulky. Skript provádí následující úkoly:• Deklaruje požadované parametry • Vytvoří dočasnou tabulku s názvem #tempstatistics k uložení názvu tabulky, názvu schématu a názvu databáze • Vytvoří další tabulku s názvem #tempdatabase pro uložení názvu databáze. Nejprve spusťte následující skript a vytvořte dvě tabulky:

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

Dále zapište while smyčku pro vytvoření dynamického SQL dotazu, který projde všemi databázemi a vloží seznam tabulek, které mají počítadlo úprav větší než 200 do #tempstatistics stůl. K získání informací o změnách dat používám sys.dm_db_stats_properties . Prostudujte si následující příklad kódu:

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

Nyní vytvořte druhou smyčku v rámci první smyčky. Vygeneruje dynamický SQL dotaz, který aktualizuje statistiky úplným skenováním. Viz příklad kódu níže:

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

Po dokončení spuštění skriptu se zruší všechny dočasné tabulky.

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

Celý skript se zobrazí následovně:

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

Tento skript můžete také automatizovat vytvořením úlohy SQL Server Agent, která jej spustí v naplánovanou dobu. Pokyny krok za krokem k automatizaci této úlohy jsou uvedeny níže.

Vytvoření úlohy SQL

Nejprve vytvořte úlohu SQL pro automatizaci procesu. Chcete-li to provést, otevřete SSMS, připojte se k požadovanému serveru a rozbalte SQL Server Agent, klikněte pravým tlačítkem na Úlohy a vyberte Nová úloha . V části Nová úloha dialogovém okně zadejte požadovaný název do Název pole. Nyní klikněte na Kroky možnost nabídky na levém panelu Nová úloha dialogovém okně a poté klikněte na Nový v části Kroky okno. V Kroku nové úlohy dialogovém okně, které se otevře, zadejte požadovaný název do Název kroku pole. Dále vyberte Skript Transact-SQL (T-SQL) v části Typ rozevíracím seznamu. Poté vyberte DBATools v Databázi rozevíracího pole a do textového pole příkazu napište následující dotaz:

EXEC Statistics_maintenance

Chcete-li nakonfigurovat plán úlohy, klikněte na Plány v nabídce Nová úloha dialogové okno. Nový rozvrh úloh otevře se dialogové okno. V části Jméno zadejte požadovaný název plánu. V našem příkladu chceme, aby se tato úloha prováděla každou noc v 1:00, tedy v Vyskytuje se v rozevíracím seznamu Frekvence vyberte možnost Denně . V části Vyskytuje se jednou v v poli Denní frekvence sekce, zadejte 01:00:00. Klikněte na OK zavřete Nový plán úloh a poté klikněte na OK znovu v Nová úloha dialogové okno jej zavřete. Nyní otestujeme tuto práci. V části SQL Server Agent klikněte pravým tlačítkem na Update_Statistics_Daily . V případě úspěšného provedení úlohy se zobrazí následující okno.

Shrnutí

V tomto článku jsou popsány následující problémy:1. Jak aktualizovat statistiku tabulek pomocí skriptu T-SQL. 2. Jak získat informace o změnách objemu dat a četnosti změn dat. 3. Jak vytvořit skript, který aktualizuje statistiky aktivních tabulek. 4. Jak vytvořit SQL Server Agent Job pro spuštění skriptu v naplánovanou dobu.


  1. CASE SQLite

  2. Android :Chyba Sqlite - (1) blízko null:chyba syntaxe

  3. Jak exportovat data z SQL Server 2005 do MySQL

  4. WHERE IN podmínka nepřijímá hodnotu řetězce