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.