Database
 sql >> база данни >  >> RDS >> Database

Разбиране какво наистина актуализира sp_updatestats

Когато бях в Чикаго преди няколко седмици за едно от нашите събития за потапяне, един от присъстващите имаше въпрос със статистически данни. Няма да навлизам във всички подробности около проблема, но присъстващият спомена, че статистиката е била актуализирана с помощта на sp_updatestats . Това е метод за актуализиране на статистически данни, който никога не съм препоръчвал; Винаги съм препоръчвал комбинация от възстановяване на индекси и UPDATE STATISTICS за да поддържате статистиката актуална. Ако не сте запознати с sp_updatestats , това е команда, която се изпълнява за цялата база данни за актуализиране на статистиката. Но както Кимбърли посочи на присъстващия, sp_updatestats ще актуализира статистика, стига да има променен един ред. уау. Веднага отворих Books Online и за sp_updatestats ще видите това:

sp_updatestats актуализира само статистическите данни, които изискват актуализиране въз основа на информацията за rowmodctr в каталожния изглед на sys.sysindexes, като по този начин се избягват ненужните актуализации на статистиката за непроменените редове

Сега, признавам, направих предположение за това какво означава "...изисква актуализиране въз основа на информацията за rowmodctr в изгледа на каталога sys.sysindexes...". Предполагах, че решението за актуализиране ще следва същата логика, която следва опцията Auto Update Statistics, която е:

  • Размерът на таблицата е нараснал от 0 до>0 реда (тест 1).
  • Броят на редовете в таблицата, когато са били събрани статистическите данни, е бил 500 или по-малко, а colmodctr на водещата колона на статистическия обект се е променил с повече от 500 оттогава (тест 2).
  • Таблицата имаше повече от 500 реда, когато статистическите данни са били събрани, а colmodctr на водещата колона на статистическия обект се е променил с повече от 500 + 20% от броя на редовете в таблицата, когато са били събрани статистическите данни ( тест 3).

Тази логика не се следва за sp_updatestats . Всъщност логиката е толкова невероятно проста, че е страшна:ако един ред е променен, статистиката се актуализира. Един ред. ЕДИН РЕД. какво ме притеснява? Притеснявам се за излишните разходи за актуализиране на статистически данни за куп статистически данни, които наистина не трябва да се актуализират. Нека разгледаме по-отблизо sp_updatestats .

Ще започнем с ново копие на базата данни AdventureWorks2012, което можете да изтеглите от Codeplex. Първо ще актуализирам редове в три различни таблици:

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

Променихме един ред в Production.Product , 211 реда в Person.Person и добавихме 10 000 реда към Sales.SalesReason . Ако sp_updatestats процедурата следва същата логика за актуализации като опцията Auto Update Statistics, след което само Sales.SalesReason ще се актуализира, защото имаше 10 реда за начало (докато 211 реда бяха актуализирани в Person.Person представляват около един процент от таблицата). Ако обаче се поразровим в sp_updatestats , можем да видим, че използваната логика е различна. Обърнете внимание, че извличам изявленията само от sp_updatestats които се използват, за да се определи каква статистика се актуализира.

Курсорът преминава през всички потребителски дефинирани таблици и вътрешни таблици в базата данни:

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

Друг курсор преглежда статистическите данни за всяка таблица и изключва купища и хипотетични индекси и статистики. Имайте предвид, че sys.sysindexes се използва в sp_helpstats . Sysindexes е системна таблица на SQL Server 2000 и е планирано да бъде премахната в бъдеща версия на SQL Server. Това е интересно, тъй като другият метод за определяне на актуализирани редове е sys.dm_db_stats_properties DMF, който е наличен само в SQL 2008 R2 SP2 и 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

След малко подготовка и допълнителна логика стигаме до IF изявление, което разкрива, че sp_updatestats филтрира статистически данни, които не са актуализирали нито един ред... потвърждавайки, че дори само един ред да е променен, статистиката ще бъде актуализирана. Има и проверка за @is_ver_current , което се определя от вградена вътрешна функция.

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

Още няколко проверки, свързани с извадката и нивото на съвместимост, а след това UPDATE оператор се изпълнява за статистиката. Преди всъщност да изпълним sp_updatestats, можем да потърсим sys.sysindexes за да видите какви статистики ще се актуализират:

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

В допълнение към трите таблици, които променихме, има още една статистика за потребителска таблица (dbo.DatabaseLog ) и три вътрешни статистики, които ще бъдат актуализирани:


Статистика, която ще бъде актуализирана

Ако стартираме sp_updatestats за базата данни AdventureWorks, изходът изброява всяка таблица и актуализираната(ите) статистика(и). Изходът по-долу е променен, за да показва само актуализирани статистически данни:

Актуализиране на [sys].[fulltext_avdl_1589580701]
[clust] бе актуализиран...
1 индекс(и)/статистика(и) бяха актуализирани, 0 не изискваше актуализиране.

Актуализиране на [dbo].[DatabaseLog]
[PK_DatabaseLog_DatabaseLogID] бе актуализиран...
1 индекс(и)/статистика(и) бяха актуализирани, 0 не изискваше актуализиране.

Актуализиране на [sys].[fulltext_avdl_1077578877]
[clust] бе актуализиран...
1 индекс(и)/статистика(и) бяха актуализирани, 0 не изискваше актуализиране.

[Person].[Person]
[PK_Person_BusinessEntityID], актуализация не е необходима...
[IX_Person_LastName_FirstName_MiddleName] е актуализирана…
[AK_Person_rowguid], не е необходима актуализация...
1 индекс(и)/статистически(и) са актуализирани, 2 не изискват актуализиране.

Актуализиране на [Sales].[SalesReason]
[PK_SalesReason_SalesReasonID] бе актуализиран…
1 индекс(и)/статистика(и) бяха актуализирани, 0 не изискваше актуализиране.

[Продукция].[Продукт]
[PK_Product_ProductID], актуализация не е необходима…
[AK_Product_ProductNumber], актуализация не е необходима…
[AK_Product_Name] е актуализирана…
[ AK_Product_rowguid], актуализация не е необходима…
[_WA_Sys_00000013_75A278F5], актуализация не е необходима…
[_WA_Sys_00000014_75A278F5], актуализация не е необходима…
0_WA_Sys_07, не е необходима актуализация<0_005/07>[_WA_Sys_0000000C_75A278F5], актуализация не е необходима...
1 индекс(и)/статистика(и) бяха актуализирани, 7 не изискваха актуализация.

Статистиката за всички таблици е актуализирана.

Последният ред на изхода е малко подвеждащ – статистическите данни за всички таблици не са актуализирани, актуализирани са само статистиките, които са имали един ред или повече модифицирани. И отново, недостатъкът на това е, че може би са използвани ресурси, които не е необходимо. Ако една статистика има променен само един ред, трябва ли да се актуализира? Не. Ако има актуализирани 10 000 реда, трябва ли да се актуализира? Е, това зависи. Ако таблицата има само 5000 реда, тогава абсолютно; ако таблицата има 1 милион реда, тогава не, тъй като само един процент от таблицата е променен.

Изводът тук е, че ако използвате sp_updatestats за да актуализирате статистиката си, най-вероятно губите ресурси, включително CPU, I/O и tempdb. Освен това е необходимо време за актуализиране на всяка статистика и ако имате ограничен прозорец за поддръжка, вероятно имате други задачи за поддръжка, които могат да се изпълнят за това време, вместо ненужни актуализации. И накрая, вероятно не предоставяте никакви ползи за производителността, като актуализирате статистическите данни, когато толкова малко редове са променени. Промяната в разпределението вероятно е незначителна, ако само малък процент от редовете са променени, така че стойностите на хистограмата и плътността не се променят толкова много. Освен това не забравяйте, че актуализирането на статистическите данни прави невалидни планове за заявки, които използват тези статистически данни. Когато тези заявки се изпълнят, плановете се генерират отново и планът вероятно ще бъде точно същият, както беше преди, тъй като нямаше значителна промяна в хистограмата. Прекомпилирането на планове за заявка има цена – не винаги е лесно да се измери, но не бива да се пренебрегва.

По-добър метод за управление на статистически данни – тъй като наистина трябва да управлявате статистиката – е да приложите планирано задание, което се актуализира въз основа на процентите на редовете, които са били променени. Можете да използвате гореспоменатата заявка, която разпитва sys.sysindexes , или можете да използвате заявката по-долу, която се възползва от новия DMF, добавен в SQL Server 2008 R2 SP2 и 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;

Осъзнайте, че различните таблици може да имат различни прагове и ще трябва да настроите заявката по-горе за вашите бази данни. За някои таблици може да е добре да се изчака, докато 15% или 20% от редовете бъдат променени. Но за други може да се наложи да актуализирате на 10% или дори 5%, в зависимост от действителните стойности и тяхното изкривяване. Няма сребърен куршум. Колкото и да обичаме абсолютите, те рядко съществуват в SQL Server и статистиката не е изключение. Все още искате да оставите статистическите данни за автоматично актуализиране активирани – това е безопасност, която ще се задейства, ако пропуснете нещо, точно като автоматичен растеж за вашите файлове с база данни. Но най-добре е да знаете данните си и да приложите методология, която ви позволява да актуализирате статистически данни въз основа на процента на променените редове.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ETL срещу ELT:Ние смятаме, вие преценете

  2. Свързване с Teradata в IRI Workbench

  3. Как да съхранявате графиците на служителите в база данни

  4. Информационни системи, данни и информация

  5. Вмъкване на DML с променлива за свързване:ИЗПОЛЗВАНЕ Клауза за изпълнение на незабавно изявление