Това е част от серия за кеширане на планове за вътрешни елементи на SQL Server. Не пропускайте да прочетете първата публикация на Kalen по тази тема.
SQL Server съществува повече от 30 години и аз работя със SQL Server почти толкова дълго. Виждал съм много промени през годините (и десетилетия!) и версии на този невероятен продукт. В тези публикации ще споделя с вас как гледам на някои от функциите или аспектите на SQL Server, понякога заедно с малко историческа перспектива
В моятапредишна статия , говорих за диагностика на SQL сървър, включително различните опции, които SQL Server има за повторно използване на план за заявка. Разгледахме три типа планове за заявки:adhoc, подготвени и процедури. Завърших дискусията с поглед към неподходящо повторно използване на план, което може да се случи, когато SQL Server прилага подслушване на параметри в грешни ситуации. Ако планът се основава на първоначална стойност, която кара оптимизатора да генерира план, подходящ за тази стойност, и след това същият план се използва за различна стойност, планът може вече да не е оптимален.
И така, какво можем да направим, когато подслушването на параметри е проблем? Можем да принудим SQL Server да излезе с нов план. Обикновено ние наричаме акта на изготвяне на нов план „прекомпилиране“, но вероятно трябва да се нарече „преоптимизиране“. Повечето хора обаче използват термина „прекомпилиране“, така че това ще използвам тук.
Ако неподходящото използване на подслушване на параметри е проблем, простото решение е просто да кажете на SQL Server да излезе с нов план. За индивидуални изрази, като например с ПОДГОТОВЛЕНИ планове, които са били автоматично параметризирани, можем да добавим подсказката RECOMPILE към заявка. Използвайки FORCED параметризирано (обсъдено в предишната статия), тази заявка ще бъде параметризирана.
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num;
Ако искаме да сме сигурни, че получаваме нов план всеки път, когато стартираме тази заявка, с потенциално много различни стойности за @num, можем да добавим подсказката RECOMPILE, както е показано:
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num
OPTION (RECOMPILE);
За съхранените процедури имаме три опции. Първо, можем да установим дали прекомпилирането действително ще помогне за производителността, като изпълним процедурата с опцията RECOMPILE:
EXEC get_sales_range 66666 WITH RECOMPILE;
Тази опция ще доведе до генериране на нов план само за това едно изпълнение. Няма да бъде запазен и със сигурност няма да бъде използван повторно. Стойността на usecount, показана в sp_cacheobjects (описана в предишната публикация) за процедурата, няма да се увеличи, тъй като оригиналният план не се използва повторно.
Второ, ако установим, че изпълнението WITH RECOMPILE помага, можем да помислим за пресъздаване на процедурата с опцията RECOMPILE, в който случай тя никога няма да използва повторно плана и процедурата изобщо няма да се покаже в кеша на плана.
DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
@num int
WITH RECOMPILE
AS
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num;
GO
За моята проста малка процедура, използването на опцията WITH RECOMPILE за цялата процедура може да има смисъл. Но ако процедурата е по-сложна, може да няма смисъл да се прекомпилира цялата процедура, защото едно изявление създава проблеми. И така, третата опция е да използвате подсказката RECOMPILE за изявление в рамките на процедурата, така че изглежда така:
DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
@num int
AS
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num
OPTION (RECOMPILE);
GO
Използването на една от тези опции RECOMPILE може да принуди SQL Server да изготви нов план по ваше желание. Сега ще разгледаме кога диагностиката на SQL Server предлага нов план, когато не го поискате, т.е. кога се извършва автоматично прекомпилиране на съществуващ план?
Автоматичното прекомпилиране на план се случва в два типа ситуации:
- Първо, ако оптимизаторът определи, че съществуващият план вече не е правилен, обикновено поради промяна в дефинициите на обекта, ще трябва да изготви нов план. Например, ако имате план за заявка, която избира от TableA, и след това пуснете няколко колони или промените типовете данни на колоните в TableA, SQL Server ще прекомпилира заявката, за да излезе с план, който отразява промените в DDL.
- Втората ситуация, при която възниква автоматично прекомпилиране, е когато SQL Server определи, че планът може вече да не е оптимален поради промяна в статистиката. В повечето случаи, ако статистическите данни за някоя от колоните или индексите са били актуализирани от последния път, когато планът е съставен, той ще бъде компилиран отново. Но това води до друг въпрос. Кога се актуализира статистиката? Статистиката може да се актуализира автоматично, когато достатъчно редове в съответните колони се променят. Колко са достатъчни? Говорим за това скоро.
По подразбиране SQL Server ще актуализира статистическите данни автоматично поради опция за база данни, която е ВКЛЮЧЕНА по подразбиране. Но ако сте собственик на база данни (или SQL „sa“, който се появява като собственик във всяка база данни), можете да промените опциите. Една от опциите се нарича AUTO_UPDATE_STATISTICS, а друга се нарича AUTO_UPDATE_STATISTICS_ASYNC. Опцията AUTO_UPDATE_STATISTICS е ON в базата данни tempdb, така че всяка нова база данни наследява тази опция. Когато тази опция е ON и машината за изпълнение на заявка открива промени в достатъчен брой редове, докато заявката се обработва, изпълнението ще спре, докато статистиката се актуализира и след това заявката се компилира отново. Другата опция, AUTO_UPDATE_STATISTICS_ASYNC, може потенциално да има по-малък ефект върху времето за изпълнение на заявката, тъй като изпълнението не е на пауза, с цената на използването на възможен неоптимален план. При втората опция, ако машината за изпълнение открие необходимост от актуализиране на статистиката, се задейства фонова нишка, за да извърши актуализацията, а основната нишка продължава да изпълнява заявката с оригиналната статистика и оригиналния план. Следващата заявка, която осъществява достъп до засегнатите таблици и вижда актуализираните статистически данни, ще прекомпилира заявката, но няма да постави на пауза и да извърши актуализирането на статистическите данни в средата на изпълнението.
Има още няколко ситуации, както и някои подсказки за заявка, които контролират дали плановете се компилират или не, така че ще ви покажа блок-схема, която ще споделя с вас, която създадох за моите обучителни класове по вътрешните елементи на SQL Server.
Стрелката е мястото, където SQL Server започва да обработва вашата партида. Първо проверява дали вече има план за вашата партида в кеша и ако отговорът е НЕ, следва стрелката вдясно и компилира план. Планът се поставя в кеша и след това SQL Server стартира отново. Да, този път планът трябва да е в кеша, така че след това следва стрелката надолу и пита дали е използван намек, наречен KEEP PLAN. Ако отговорът е ДА, SQL Server започва да изпълнява плана незабавно и не прави допълнителни проверки.
Следващият въпрос е дали са направени промени в DDL. Ако не, пита се за няколко други ситуации, за които няма да мога да говоря в тази статия. Всъщност тук наистина няма да прекрача всяка опция. ще оставя това на вас. Но ако имате някакви въпроси или обърквания, не се колебайте да ги зададете в секцията за коментари тук или ми пишете в туит на @sqlqueen. Ще посоча въпроса най-вдясно:Включено ли е AUTO_STATS_ASYNC? Тук можете да видите, че ако отговорът е ДА, има две действия. Единият клон просто започва да се изпълнява със съществуващия план, а другият е фоновата нишка, която актуализира статистическите данни, но след това не прави нищо друго. Следващата заявка ще срещне полето за решение в средата „Налични ли са нови статистически данни“ и трябва да отговори ДА, така че заявката ще бъде прекомпилирана.
Единственото друго нещо, за което ще говоря, е въпросът „Някаква статистика остаряла ли е?“ Това основно означава, че статистиката е остаряла, защото са направени твърде много промени. Така че сега можем да говорим за това колко са твърде много.
Въпреки че има различни стойности, използвани за много малки таблици, за всяка таблица с повече от 500 реда в нея, преди SQL Server 2016, статистиката ще се счита за „застояла“, когато броят на промените в колоната, на която се базират статистическите данни, надвиши 20 % от броя на редовете в таблицата. Така че за таблица от 1000 реда това може да означава 200 вмъквания, 200 актуализации или 200 изтривания. Може да са промени в 200 реда или 5 реда, актуализирани 40 пъти всеки. SQL Server дори ни дава функция, която отчита колко промени са направени. Ще трябва да потърсите номера stats_id за статистическите данни, които ви интересуват, което би било index_id, ако статистическите данни принадлежат към индекс. Stats_id може да бъде намерен в изгледа, наречен sys.stats. В моята таблица за новини използвам тази заявка, за да открия, че stats_id за индекса в колоната SubTotal е 3.
SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');
След това мога да използвам тази стойност, за да разгледам броя на промените. Нека първо актуализирам някои редове:
UPDATE newsales
(засегнати 1541 реда)
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);
Всъщност 20% е ГОЛЯМО число. И за много таблици заявките може да се възползват от актуализирана статистика с много по-малко от 20% от актуализираните редове. Започвайки от 2008R2 SP1, SQL Server включва Traceflag, който можете да използвате, за да промените броя на редовете, за да бъде плъзгаща се скала, както е показано на следната графика:
Започвайки от SQL Server 2016, този нов алгоритъм с плъзгаща се скала се използва по подразбиране, стига да сте на ниво на съвместимост 130 или по-високо.
Повечето автоматични прекомпилации на планове за заявки се дължат на промени в статистиката. Но както споменах по-горе, това не е единствената причина за прекомпилиране. Но тъй като е най-често срещаният, може да бъде много полезно да сте наясно кога и как се актуализират статистическите данни и да се уверите, че статистическите данни във вашите критични таблици се актуализират достатъчно често, за да сте сигурни, че получавате най-добрите планове!
Анализирайте данните за производителността автоматично, за да извършите диагностика на SQL сървър, за да разрешите бързо проблемите и да идентифицирате сървърите, където произтича влошаване на производителността. Започнете да използвате Spotlight Cloud днес: