Още през април писах за някои естествени методи в SQL Server, които могат да се използват за проследяване на автоматични актуализации на статистиката. Трите опции, които предоставих, бяха SQL Trace, Extended Events и моментни снимки на sys.dm_db_stats_properties. Въпреки че тези три опции остават жизнеспособни (дори в SQL Server 2014, въпреки че моята най-добра препоръка все още е XE), допълнителна опция, която забелязах при провеждането на някои тестове наскоро, е SQL Sentry Plan Explorer.
Много от вас използват Plan Explorer просто за четене на изпълнявани планове, което е страхотно. Той има много предимства пред Management Studio, когато става въпрос за преглед на планове – от малки неща, като възможността да сортирате най-добрите оператори и лесно да виждате проблеми с оценката на кардиналността, до по-големи предимства, като обработка на сложни и големи планове и възможност за избор на един изявление в рамките на партида за по-лесен преглед на плана. Но зад визуалните елементи, които улесняват дисекцията на планове, Plan Explorer предлага също възможност за изпълнение на заявка и преглед на действителния план (вместо да го изпълнявате в Management Studio и да го запазвате). И на всичкото отгоре, когато стартирате плана от PE, има уловена допълнителна информация, която може да бъде полезна.
Нека започнем с демонстрацията, която използвах в скорошната си публикация, Как автоматичните актуализации на статистиката могат да повлияят на производителността на заявката. Започнах с базата данни AdventureWorks2012 и създадох копие на таблицата SalesOrderHeader с над 200 милиона реда. Таблицата има клъстериран индекс на SalesOrderID и неклъстериран индекс на CustomerID, OrderDate, SubTotal. [Отново:ако ще правите повторни тестове, направете резервно копие на тази база данни в този момент, за да си спестите известно време.] Първо проверих текущия брой редове в таблицата и броя на редовете, които ще трябва да се променят за да извикате автоматична актуализация:
SELECT OBJECT_NAME([p].[object_id]) [TableName], [si].[name] [IndexName], [au].[type_desc] [Type], [p].[rows] [RowCount], ([p].[rows]*.20) + 500 [UpdateThreshold], [au].total_pages [PageCount], (([au].[total_pages]*8)/1024)/1024 [TotalGB] FROM [sys].[partitions] [p] JOIN [sys].[allocation_units] [au] ON [p].[partition_id] = [au].[container_id] JOIN [sys].[indexes] [si] on [p].[object_id] = [si].object_id and [p].[index_id] = [si].[index_id] WHERE [p].[object_id] = OBJECT_ID(N'Sales.Big_SalesOrderHeader');
Big_SalesOrderHeader Информация за CIX и NCI
Проверих и текущата заглавка на статистиката за индекса:
DBCC SHOW_STATISTICS ('Sales.Big_SalesOrderHeader',[IX_Big_SalesOrderHeader_CustomerID_OrderDate_SubTotal]);
Статистика на NCI:в началото
Съхранената процедура, която използвам за тестване, вече е създадена, но за пълнота кодът е посочен по-долу:
CREATE PROCEDURE Sales.usp_GetCustomerStats @CustomerID INT, @StartDate DATETIME, @EndDate DATETIME AS BEGIN SET NOCOUNT ON; SELECT CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate), COUNT([SalesOrderID]) as Computed FROM [Sales].[Big_SalesOrderHeader] WHERE CustomerID = @CustomerID AND OrderDate BETWEEN @StartDate and @EndDate GROUP BY CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate) ORDER BY DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate); END
Преди това или стартирах сесия за проследяване или разширени събития, или настроих своя метод за моментна снимка sys.dm_db_stats_properties към таблица. За този пример просто изпълних горепосочената съхранена процедура няколко пъти:
EXEC Sales.usp_GetCustomerStats 11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 11506, '2012-11-01 00:00:00.000', '2012-11-30 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 11711, '2013-03-01 00:00:00.000', '2013-03-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997' GO EXEC Sales.usp_GetCustomerStats 15750, '2013-03-01 00:00:00.000', '2013-03-31 23:59:59.997' GO
След това проверих кеша на процедурите, за да проверя броя на изпълнението, и също така проверих кеширания план:
SELECT OBJECT_NAME([st].[objectid]), [st].[text], [qs].[execution_count], [qs].[creation_time], [qs].[last_execution_time], [qs].[min_worker_time], [qs].[max_worker_time], [qs].[min_logical_reads], [qs].[max_logical_reads], [qs].[min_elapsed_time], [qs].[max_elapsed_time], [qp].[query_plan] FROM [sys].[dm_exec_query_stats] [qs] CROSS APPLY [sys].[dm_exec_sql_text]([qs].plan_handle) [st] CROSS APPLY [sys].[dm_exec_query_plan]([qs].plan_handle) [qp] WHERE [st].[text] LIKE '%usp_GetCustomerStats%' AND OBJECT_NAME([st].[objectid]) IS NOT NULL;
Информация за кеша за планиране за SP:В началото
План за заявка за съхранена процедура, използвайки SQL Sentry Plan Explorer
Планът е създаден на 29.09.2014 23:23.01.
След това добавих 61 милиона реда към таблицата, за да обезсиля текущата статистика и след като вмъкването приключи, проверих броя на редовете:
Big_SalesOrderHeader Информация за CIX и NCI:След вмъкване на 61 милиона редове
Преди да стартирам отново съхранената процедура, проверих, че броят на изпълнението не се е променил, че времето за създаване все още е 2014-09-29 23:23.01 за плана и че статистиката не се е актуализирала:
Информация за кеш на плана за SP:Веднага след вмъкване
NCI статистика:след вмъкване
Сега, в предишната публикация в блога, изпълних изявлението в Management Studio, но този път изпълних заявката директно от Plan Explorer и заснех действителния план чрез PE (опция, оградена в червено на изображението по-долу).
Изпълнете съхранена процедура от Plan Explorer
Когато изпълните изявление от PE, трябва да въведете екземпляра и базата данни, към които искате да се свържете, и след това ще бъдете уведомени, че заявката ще се изпълни и действителният план ще бъде върнат, но резултатите няма да бъдат върнати. Имайте предвид, че това е различно от Management Studio, където виждате резултатите.
След като стартирах съхранената процедура, в изхода не само получавам плана, но виждам какви оператори са били изпълнени:
Планирайте изход на Explorer след изпълнение SP (след вмъкване)
Това е доста готино… освен че виждам оператора, изпълнен в съхранената процедура, виждам и актуализациите на статистиката, точно както направих, когато заснех актуализации с помощта на разширени събития или SQL Trace. Заедно с изпълнението на оператора, можем също да видим информация за процесора, продължителността и IO. Сега – предупреждението тук е, че мога да видя тази информация if Изпълнявам изявлението, което извиква актуализацията на статистиката от Plan Explorer. Това вероятно няма да се случва често във вашата производствена среда, но може да видите това, когато правите тестване (защото се надяваме, че тестването ви не включва само изпълнение на заявки SELECT, но включва и заявки INSERT/UPDATE/DELETE точно както бихте направили вижте при нормално натоварване). Въпреки това, ако наблюдавате средата си с инструмент като SQL Sentry, може да видите тези актуализации в Top SQL стига да надвишават прага за събиране на Top SQL. SQL Sentry има прагове по подразбиране, които заявките трябва да надхвърлят, преди да бъдат уловени като най-добрия SQL (например продължителността трябва да надвишава пет (5) секунди), но можете да ги промените и да добавите други прагове, като например четения. В този пример само за тестови цели , промених моя праг за минимална продължителност на най-добрия SQL на 10 милисекунди и моя праг за четене на 500 и SQL Sentry успя да улови някои от актуализациите на статистиката:
Актуализации на статистиката, заснети от SQL Sentry
Въпреки това, дали мониторингът може да улови тези събития в крайна сметка ще зависи от системните ресурси и количеството данни, които трябва да бъдат прочетени, за да се актуализира статистиката. Вашите актуализации на статистическите данни може да не надхвърлят тези прагове, така че може да се наложи да направите по-проактивно копаене, за да ги намерите.
Резюме
Винаги насърчавам администраторите на база данни да управляват проактивно статистиката – което означава, че има работа за редовно актуализиране на статистиката. Въпреки това, дори ако това задание се изпълнява всяка вечер (което не препоръчвам непременно), все пак е напълно възможно актуализациите на статистическите данни да се извършват автоматично през деня, тъй като някои таблици са по-нестабилни от други и имат голям брой модификации. Това не е необичайно и в зависимост от размера на таблицата и количеството на модификациите, автоматичните актуализации може да не пречат значително на потребителските заявки. Но единственият начин да разберете е да наблюдавате тези актуализации – независимо дали използвате собствени инструменти или инструменти на трети страни – за да можете да сте пред потенциалните проблеми и да ги адресирате, преди да ескалират.