През изминалите две сряди бяхме домакин на серия от две части от уебинари, третиращи проблеми с чувствителността на параметрите:
- Запазени процедури, параметри, проблеми...
Кимбърли Л. Трип и Арън Бертран
24 януари
Пропуснали ли сте? Регистрирайте се, за да го гледате сега! - Справяне с подслушването на параметри с помощта на SentryOne
Аарон Бертран, Кимбърли Л. Трип и Анди Малън
31 януари
Пропуснахте ли го? Гледайте го сега!
По време на двата уебинара се появиха някои въпроси и реших да ги съставя и да им отговоря тук (някои от отговорите дойдоха от Анди по време на уебинара).
В проблем, който видяхме наскоро, виждаме, че плановете се отпадат от кеша много бързо. Не изпълняваме нищо, което описвате (
DBCC FREEPROCCACHE
и др.); може ли напрежението в паметта също да причини това?
Да, напрежението в паметта може да бъде фактор (вижте тази публикация) и знам, че има някои разследвания на потенциални проблеми с управлението на паметта на SQL Server и в това отношение.
От присъстващ:„Не въпрос, а коментар към потребителя, който пита колко пъти кешът на плана му се изпразва. Имахме и това и наистина беше натиск върху паметта. Имахме грешно конфигурирана максимална памет на сървъра, т.е. коригирано с помощта на формулата, спомената тук, и след това процедурата от тази статия се изпълнява на всеки 10 минути (имаме тонове динамичен SQL, използван само веднъж)."
Ами ако използвате
OR
в клаузата where вместоAND
, проблемът ще продължи ли?
Обикновено, ако използвате
OR
в този тип шаблон вие ще получавате всички редове всеки път, освен ако всеки един параметър не е попълнен със стойности, които филтрират редовете. Това променя семантиката на заявката от „всички тези неща трябва да са верни“ на „всяко едно от тези неща може да бъде вярно“. Все пак планът, който е компилиран за първия набор от параметри, ще продължи да бъде кеширан и запазен за бъдещи изпълнения, независимо дали вашите клаузи използватAND
илиOR
.
Това
1=1
ли е флаг добър подход? Не е ли по-добре да добавите само предоставените параметри и следователно да избегнете грозното1=1
?
1 = 1
на практика се игнорира от SQL Server, но позволява всички условни клаузи да бъдат добавени сAND
за да не се налага да третирате *първия* по различен начин. Ето алтернативата:SET @IncludedWhereClauseYet bit = 0; SET @sql = N'SELECT cols FROM dbo.Table'; IF @param1 IS NOT NULL BEGIN IF @IncludedWhereClauseYet = 0 BEGIN SET @sql += N' WHERE '; SET @IncludedWhereClauseYet = 1; END ELSE BEGIN SET @sql += N' AND '; END SET @sql += N' @param1 = @param1'; END IF @param2 IS NOT NULL BEGIN IF @IncludedWhereClauseYet = 0 ... END ...
1=1
ви позволява да опростите, като ви позволява винаги да поставяте префикс на всяка клауза сAND
. Горният код става:SET @sql = N'SELECT cols FROM dbo.Table WHERE 1 = 1'; IF @param1 IS NOT NULL BEGIN SET @sql += N' AND @param1 = @param1'; END IF @param2 IS NOT NULL BEGIN SET @sql += N' AND @param2 = @param2'; ENDМоже би бихте могли да използвате различна начална клауза, за да избегнете всички условия, като
WHERE PrimaryKey > 0
илиWHERE PrimaryKey IS NOT NULL
, а след това всяка следваща клауза може да започва сAND
. Но1 = 1
, макар и грозен, е безобиден и IMHO е не по-малко грозен от добавянето на *real*, но безсмислена клауза, с изключение на това, че *real* клауза може да повлияе на плана.Не забравяйте, че когато конструирате T-SQL код с T-SQL, имате два аспекта на „грозно“ за обмисляне – понякога ще отстранявате проблеми с кода по-горе, а понякога ще отстранявате неизправности в заявката, която излиза от то. Внимавайте да жертвате едното в името на другото.
КАКВО?! Напълно пропуснах това ...
WITH RECOMPILE
. Мислех, че това изпразни плана, но го оставя само за това изпълнение... това е много важно да знаете!
Просто се уверете, че сте наясно и с недостатъците.
Вижте тази страхотна публикация от Пол Уайт.
Е
OPTION OPTIMIZE FOR @parametername UNKNOWN
вече не се предпочита в по-новите версии на SQL?
Не мисля, че е по-добър или по-лош в съвременните версии, отколкото когато беше представен за първи път в SQL Server 2008. Доколкото знам, дори с всички промени в оптимизатора и оценката на мощността, този бит продължава да се държи по същия начин.
Има ли някакво натоварване на сървъра, ако разреша заснемането на статистически данни за процедурите и статистики на заявки в SentryOne?
Колекцията от статистически данни за процедури и заявки трябва да е включена по подразбиране. Цялото събиране на данни идва с цена, но SQL Sentry е доста внимателен за това колко разходи са направени от събирането.
Търсенето на RS не го използваше като остатъчен предикат, търсеше нещо друго, което не можах да видя.
Благодаря, ще прегледам този пример и ще направя блог за демонстрациите отделно, като се уверя, че включвам всички подходящи подробности, които не са очевидни само от диаграмата на плана.
Не е ли вярно, че добавянето на някои от колоните е необходимо като
INCLUDE
s всъщност не прави индекса по-ефективен, защото търсенето на ключове няма да бъде елиминирано? Мисля, че процентът не трябва да се променя, освен ако всъщност не елиминирате търсенето на ключове.
Строго, да, това е вярно. Оригиналната заявка беше изключително лош пример, използвайки
SELECT *
и индекс, в който липсва безнадежден брой колони. Това, което се опитвах да кажа, е, че разделът Анализ на индекса ви насърчава както (а) да подобрите заявката, така и (б) да направите корицата на индекса. Резултатът е там, за да ви примами да направите едното или и двете – ако промените заявката, така че имате нужда от по-малко колони, индексът се доближава до покриване на заявката. Ако възнамерявате да създадете нов, отделен, покриващ индекс, вие също имате информация за това кои колони са необходими за покриване на тази конкретна заявка. Технически си прав, добавянето на една колона за включване, но все пак изискването за търсене за 4 други няма да направи тази конкретна заявка да работи по-добре и няма да направи индекса по-добър, но показва, че се приближават. Надеждата е, че няма да спрете само да добавите една колона за включване и да игнорирате останалите. Не знаем кога ще спрете, така че не знам дали има идеално решение – със сигурност не искаме да обезкуражаваме потребителите да направят своите индекси по-подходящи за техните заявки.
Защо виждаме заявки, използващи параметър за име и параметър за фамилия, обобщени под изявление, използващо само параметър на фамилията?
АКТУАЛИЗИРАНЕ: Това е умишлено. Групирането под Show Totals групира същата процедура, извикана с всички различни комбинации от параметри. Така че можете първо да го използвате, за да определите кои параметри са склонни да причинят най-лошата производителност, след което в рамките на това да се разработите дали има изкривяване на данните или не. Параметър, който води до търсене срещу неиндексирана колона, например, вероятно ще се появи най-отгоре доста надеждно и можете да видите това в комбинация с други параметри, които се предават и също така се сравняват с всички извиквания, където е бил този параметър. t премина.
След като казахме всичко това, ще потърсим фина настройка на това поведение на групиране, докато завършим текущите промени за най-горния екран на SQL.
Има ли някаква документация как да използвате ръководство за план? В момента нямам идея как да направя това.
Това е нещо друго, за което исках да пиша в блог, но Microsoft има някои теми тук междувременно (и вижте всички свързани връзки в страничната лента).
Трябва ли да активирам нещо, за да получа диаграма на историята на заявките?
Не, това трябва да бъде активирано във всички съвременни версии на клиентското приложение SentryOne. Ако не го виждате, опитайте
Tools > Reset Layout
; ако това не работи, свържете се с [email protected].
Има ли случаи, когато форсирането на последния известен добър план с помощта на Query Store, когато регресията на плана се счита за лоша идея? Това ще има ли тенденция да скрие проблеми, които се решават по-добре чрез промяна на изявлението, както показахте?
Принудителното изпълнение на план често е опция в краен случай и аз съм склонен да го резервирам за случаи, когато наистина, наистина, наистина не можете да коригирате изявлението (или да промените индекса). Насилването на план винаги може да доведе до грешно поведение, защото все пак човек прави този избор и вие може да го направите въз основа на лоша информация. Регресията може да се дължи на промяна на плана, но ако го оценявате като регресия, тъй като времето за изпълнение е по-дълго, проучили ли сте други възможни причини? Например, да кажем, че системата е била рестартирана или е имало отказ и е получил нов план, защото старият е бил изгонен и може би междувременно статистиката също е променена, но сега заявката работи по-дълго не защото планът е по-лош, а по-скоро защото буферите бяха празни. Така че да, със сигурност не бих предложил да налагате план за всяка регресия.
SentryOne не винаги улавя данни или параметри през цялото време, така че нямам достатъчно информация. Как да се уверя, че SentryOne улавя параметри и планове за изпълнение през цялото време?
Наистина не можете, защото всичко се свежда до това как се изпълняват вашите заявки, как ги улавяме и колко бързо се изпълняват. Често вашите заявки не се изпълняват достатъчно дълго, за да бъдат уловени напълно, и ние трябва да разчитаме на обобщените изгледи на заявка/процедура на SQL Server, които не събират информация за параметрите. Можете да промените настройките за събиране на най-добрия SQL източник, за да улавяте повече и на по-чести интервали, но трябва да балансирате количеството данни, които събирате, с това колко допълнителна информация ви купува.
Мога ли да потърся информация, за да мога да автоматизирам и генерирам отчети?
Нямаме нищо извън кутията, с което да направите това, но нека го върна на екипа и да видим какви опции можем да измислим. Едно нещо, с което се заиграх за този уебинар, беше да създам консултативно условие, за да уловя видовете регресии, които търсим, но времето стана фактор.
Как да решим кога да използваме
OPTION (RECOMPILE)
, както всеки ден получаваме различни планове за различни параметри?
Бих казал, че започнете със заявките, които се колебаят най-много с чувствителността на параметрите. Ако имам заявка, която понякога отнема 2 секунди, но понякога 30 и друга, която варира от 4 секунди до 6 секунди,
ще се съсредоточа върху първата.
Коя е по-добре да използвате,
OPTION (RECOMPILE)
илиQUERYTRACEON
, в случай на подслушване на параметри.
Предпочитам
OPTION (RECOMPILE)
поради две причини. Първо, самодокументира се; никой, който чете кода, няма да се чуди какво прави, но не всеки, който чете кода, ще има запомнени TF номера като 4136. Второ, не изисква повишени разрешения – опитайте да използватеQUERYTRACEON
като пеон.
Възможно ли е да се предупреждава или докладва за процедури, които отнемат повече време от обикновено? Най-много се интересуват от процедури с голям брой.
Абсолютно можете да използвате консултативно условие, но може да стане малко сложно, защото – за процедури, които дори понякога се изпълняват под прага за събиране – ще трябва да сравните моментни снимки на DMV статистиката на процедурата. Добавих напомняне към блога и за това, тъй като това е нещо, което съм помагал на клиентите да приложат в миналото.
Microsoft прави автоматичната настройка по подразбиране за Azure SQL база данни, включително автоматична корекция на плана. Това ли ви се струва добра идея?
Ще си запазя преценката, докато аз (или някои клиенти) не се заиграя с него. Решаването как да се настройва е достатъчно предизвикателство за простосмъртните; смъртните да пишат софтуер, който да настроят за вас, изглежда поне толкова предизвикателно, ако не и повече. Когато Анди видя този въпрос, той ми спомена, че му напомня за SQL Server 2000 – тогава маркетинговата идея беше, че е толкова самонастройваща се, че вече няма да се нуждаем от DBA. Това твърдение не е остаряло добре.
Би било хубаво да можете да изберете двете точки в диаграмата на историята на заявките и да ги сравните.
Съгласен съм.
Оставайте в течение.