sql >> Databáze >  >> RDS >> Database

Pochopení toho, co sp_updatestats skutečně aktualizuje

Když jsem byl před několika týdny v Chicagu na jedné z našich akcí Immersion, jeden účastník měl otázku ohledně statistik. Nebudu zacházet do všech podrobností o problému, ale účastník zmínil, že statistiky byly aktualizovány pomocí sp_updatestats . Toto je metoda aktualizace statistik, kterou jsem nikdy nedoporučoval; Vždy jsem doporučoval kombinaci přestavby indexu a UPDATE STATISTICS udržovat statistiky aktuální. Pokud neznáte sp_updatestats , je to příkaz, který se spouští pro celou databázi za účelem aktualizace statistik. Ale jak Kimberly upozornila účastníka, sp_updatestats aktualizuje statistiku, pokud byl v ní upraven jeden řádek. Páni. Okamžitě jsem otevřel Books Online a pro sp_updatestats uvidíte toto:

sp_updatestats aktualizuje pouze statistiky, které vyžadují aktualizaci, na základě informací rowmodctr v zobrazení katalogu sys.sysindexes, čímž se vyhnete zbytečným aktualizacím statistik na nezměněných řádcích.

Nyní, přiznávám, jsem předpokládal, co znamená „…vyžadovat aktualizaci na základě informací rowmodctr v zobrazení katalogu sys.sysindexes…“. Předpokládal jsem, že rozhodnutí o aktualizaci se bude řídit stejnou logikou jako možnost Auto Update Statistics, což je:

  • Velikost tabulky se změnila z 0 na>0 řádků (test 1).
  • Počet řádků v tabulce při shromažďování statistik byl 500 nebo méně a colmodctr úvodního sloupce objektu statistiky se od té doby změnil o více než 500 (test 2).
  • Tabulka měla více než 500 řádků, když byly shromážděny statistiky, a colmodctr úvodního sloupce objektu statistiky se změnil o více než 500 + 20 % počtu řádků v tabulce, když byly statistiky shromážděny ( test 3).

Tato logika není dodržena pro sp_updatestats . Ve skutečnosti je logika tak neuvěřitelně jednoduchá, až je to děsivé:Pokud se změní jeden řádek, statistika se aktualizuje. Jedna řada. JEDNA ŘADA. co mě znepokojuje? Obávám se režijních nákladů na aktualizaci statistik pro spoustu statistik, které skutečně není třeba aktualizovat. Podívejme se blíže na sp_updatestats .

Začneme s novou kopií databáze AdventureWorks2012, kterou si můžete stáhnout z Codeplex. Nejprve aktualizuji řádky ve třech různých tabulkách:

USE [AdventureWorks2012];
GO
SET NOCOUNT ON;
GO
 
UPDATE [Production].[Product]
SET [Name] = 'Bike Chain'
WHERE [ProductID] = 952;
 
UPDATE [Person].[Person]
SET [LastName] = 'Cameron'
WHERE [LastName] = 'Diaz';
GO
 
INSERT INTO Sales.SalesReason
(Name, ReasonType, ModifiedDate)
VALUES('Stats', 'Test', GETDATE());
GO 10000

Upravili jsme jeden řádek v Production.Product , 211 řádků v Person.Person a přidali jsme 10 000 řádků do Sales.SalesReason . Pokud sp_updatestats postup se řídil stejnou logikou pro aktualizace jako možnost Auto Update Statistics, pak pouze Sales.SalesReason by se aktualizovalo, protože na začátku mělo 10 řádků (zatímco 211 řádků bylo aktualizováno v Person.Person představují asi jedno procento tabulky). Pokud se však ponoříme do sp_updatestats , můžeme vidět, že použitá logika je jiná. Všimněte si, že výpisy extrahuji pouze z sp_updatestats které se používají k určení, jaké statistiky se aktualizují.

Kurzor prochází všemi uživatelsky definovanými tabulkami a interními tabulkami v databázi:

declare ms_crs_tnames cursor local fast_forward read_only for
select name, object_id, schema_id, type from sys.objects o
where o.type = 'U' or o.type = 'IT'
open ms_crs_tnames
fetch next from ms_crs_tnames into @table_name, @table_id, @sch_id, @table_type

Jiný kurzor prochází statistiky pro každou tabulku a vylučuje haldy a hypotetické indexy a statistiky. Všimněte si, že sys.sysindexes se používá v sp_helpstats . Sysindexes je systémovou tabulkou SQL Server 2000 a její odstranění je naplánováno v budoucí verzi SQL Server. To je zajímavé, protože další způsob, jak určit aktualizované řádky, je sys.dm_db_stats_properties DMF, který je k dispozici pouze v SQL 2008 R2 SP2 a SQL 2012 SP1.

set @index_names = cursor local fast_forward read_only for
select name, indid, rowmodctr
from sys.sysindexes
where id = @table_id
and indid > 0
and indexproperty(id, name, 'ishypothetical') = 0
order by indid

Po chvíli příprav a dodatečné logiky se dostáváme k IF prohlášení, které odhaluje, že sp_updatestats odfiltruje statistiky, u kterých nebyly aktualizovány žádné řádky... a potvrdí, že i když byl změněn pouze jeden řádek, statistika bude aktualizována. Je zde také kontrola @is_ver_current , která je určena vestavěnou vnitřní funkcí.

if ((@ind_rowmodctr <> 0) or ((@is_ver_current is not null) and (@is_ver_current = 0)))

Několik dalších kontrol týkajících se vzorkování a úrovně kompatibility a poté UPDATE příkaz se provede pro statistiku. Než sp_updatestats skutečně spustíme, můžeme se zeptat na sys.sysindexes abyste viděli, jaké statistiky se aktualizují:

SELECT [o].[name], [si].[indid], [si].[name], [si].[rowmodctr], [si].[rowcnt], [o].[type]
FROM [sys].[objects] [o]
JOIN [sys].[sysindexes] [si] ON [o].[object_id] = [si].[id]
WHERE ([o].[type] = 'U' OR [o].[type] = 'IT')
AND [si].[indid] > 0
AND [si].[rowmodctr] <> 0
ORDER BY [o].[type] DESC, [o].[name];

Kromě tří tabulek, které jsme upravili, existuje další statistika pro tabulku uživatelů (dbo.DatabaseLog ) a tři interní statistiky, které budou aktualizovány:


Statistiky, které budou aktualizovány

Pokud spustíme sp_updatestats pro databázi AdventureWorks výstup uvádí všechny tabulky a aktualizované statistiky. Níže uvedený výstup je upraven tak, aby zobrazoval pouze aktualizované statistiky:

Aktualizace [sys].[fulltext_avdl_1589580701]
[clust] byl aktualizován…
1 index(y)/statistiky(y) byly aktualizovány, 0 nevyžadovalo aktualizaci.

Aktualizace [dbo].[DatabaseLog]
[PK_DatabaseLog_DatabaseLogID] bylo aktualizováno…
1 index(y)/statistiky(y) byly aktualizovány, 0 nevyžadovalo aktualizaci.

Aktualizace [sys].[fulltext_avdl_1077578877]
[clust] byl aktualizován…
1 index(y)/statistiky(y) byly aktualizovány, 0 nevyžadovalo aktualizaci.

Aktualizace [Person].[Person]
[PK_Person_BusinessEntityID], aktualizace není nutná…
[IX_Person_LastName_FirstName_MiddleName] byla aktualizována…
[AK_Person_rowguid], aktualizace není nutná…
1 index(y)/statistika(y) byly aktualizovány, 2 nevyžadovaly aktualizaci.

Aktualizace [Sales].[SalesReason]
[PK_SalesReason_SalesReasonID] bylo aktualizováno…
1 index(y)/statistiky(y) byly aktualizovány, 0 nevyžadovalo aktualizaci.

Aktualizace [Product][Product]
[PK_Product_ProductID], aktualizace není nutná…
[AK_Product_ProductNumber], aktualizace není nutná…
[AK_Product_Name] byl aktualizován…
[ AK_Product_rowguid], aktualizace není nutná…
[_WA_Sys_00000013_75A278F5], aktualizace není nutná…
[_WA_Sys_00000014_75A278F5], aktualizace není nutná…
5A5_0A08/08…5 není nutná>[_WA_Sys_0000000C_75A278F5], aktualizace není nutná…
1 index(y)/statistika(y) byly aktualizovány, 7 nevyžadovalo aktualizaci.

Statistiky pro všechny tabulky byly aktualizovány.

Poslední řádek výstupu je trochu zavádějící – statistiky pro všechny tabulky nebyly aktualizovány, byly aktualizovány pouze statistiky, které měly jeden nebo více úprav. A opět, nevýhodou toho je, že možná byly použity zdroje, které nemusely být. Pokud má statistika upravený pouze jeden řádek, měla by být aktualizována? Ne. Má-li být aktualizováno 10 000 řádků? No, to záleží. Pokud má tabulka pouze 5 000 řádků, pak absolutně; pokud má tabulka 1 milion řádků, pak ne, protože bylo upraveno pouze jedno procento tabulky.

Shrnutí zde je, že pokud používáte sp_updatestats Chcete-li aktualizovat své statistiky, pravděpodobně plýtváte zdroji, včetně CPU, I/O a tempdb. Aktualizace každé statistiky navíc nějakou dobu trvá, a pokud máte omezené okno údržby, pravděpodobně máte jiné úkoly údržby, které lze za tu dobu provést, namísto zbytečných aktualizací. A konečně, aktualizace statistiky, když se změnilo tak málo řádků, pravděpodobně neposkytuje žádné výhody v oblasti výkonu. Změna distribuce je pravděpodobně nevýznamná, pokud bylo upraveno pouze malé procento řádků, takže hodnoty histogramu a hustoty se nakonec tolik nezmění. Kromě toho nezapomeňte, že aktualizace statistik znehodnotí plány dotazů, které tyto statistiky používají. Když se tyto dotazy provedou, plány se znovu vygenerují a plán bude pravděpodobně úplně stejný jako předtím, protože v histogramu nedošlo k žádné významné změně. Překompilování plánů dotazů něco stojí – není vždy snadné to měřit, ale neměli byste to ignorovat.

Lepší metodou pro správu statistik – protože statistiku musíte spravovat – je implementace naplánované úlohy, která se aktualizuje na základě procenta řádků, které byly upraveny. Můžete použít výše uvedený dotaz, který se dotazuje sys.sysindexes , nebo můžete použít dotaz níže, který využívá nové DMF přidané v SQL Server 2008 R2 SP2 a SQL Server 2012 SP1:

SELECT [sch].[name] + '.' + [so].[name] AS [TableName] ,
[ss].[name] AS [Statistic],
[sp].[last_updated] AS [StatsLastUpdated] ,
[sp].[rows] AS [RowsInTable] ,
[sp].[rows_sampled] AS [RowsSampled] ,
[sp].[modification_counter] AS [RowModifications]
FROM [sys].[stats] [ss]
JOIN [sys].[objects] [so] ON [ss].[object_id] = [so].[object_id]
JOIN [sys].[schemas] [sch] ON [so].[schema_id] = [sch].[schema_id]
OUTER APPLY [sys].[dm_db_stats_properties]([so].[object_id],
[ss].[stats_id]) sp
WHERE [so].[type] = 'U'
AND [sp].[modification_counter] > 0
ORDER BY [sp].[last_updated] DESC;

Uvědomte si, že různé tabulky mohou mít různé prahové hodnoty a budete muset vyladit výše uvedený dotaz pro vaše databáze. U některých tabulek může být v pořádku čekání, dokud nebude upraveno 15 % nebo 20 % řádků. Ale pro ostatní možná budete muset aktualizovat na 10 % nebo dokonce 5 %, v závislosti na skutečných hodnotách a jejich zkreslení. Neexistuje žádná stříbrná kulka. Jakkoli milujeme absolutní údaje, na SQL Serveru existují jen zřídka a statistiky nejsou výjimkou. Stále chcete nechat statistiku automatických aktualizací zapnutou – je to bezpečnostní opatření, které se spustí, pokud něco zapomenete, stejně jako automatický růst pro vaše databázové soubory. Nejlepší však je znát svá data a implementovat metodologii, která vám umožní aktualizovat statistiky na základě procenta změněných řádků.


  1. Generování dat a kvalita hardwaru

  2. Použití Aria Storage Engine se serverem MariaDB

  3. Získejte v Oracle pouze datum bez času

  4. Jak provést aktualizaci + připojit se k PostgreSQL?