Коли раніше швидкий SQL-запит починає повільно, де я шукаю джерело проблеми?


36

Фон

У мене працює запит проти SQL Server 2008 R2, який приєднує та / або залишає об'єднання приблизно 12 різних "таблиць". База даних досить велика: багато таблиць розміром понад 50 мільйонів і приблизно 300 різних таблиць. Це для великої компанії, яка має 10 складів по всій країні. Усі склади читають і записують у базу даних. Тож він досить великий і досить зайнятий.

Запит, з яким я маю проблеми, виглядає приблизно так:

select t1.something, t2.something, etc.
from Table1 t1
    inner join Table2 t2 on t1.id = t2.t1id
    left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
    [etc]...
where t1.something = 123

Зауважте, що одне з об'єднань знаходиться на некорельованому підзапиті.

Проблема полягає в тому, що починаючи сьогодні вранці, без будь-яких змін (про які я знаю я або хтось із моєї команди) до системи, запит, який зазвичай займає близько 2 хвилин, почав займати півтори години - коли це бігав зовсім. Інша база даних гуде просто чудово. Я взяв цей запит із проростка, який він зазвичай запускається, і я запускав його в змінних параметрів SSMS з жорстко кодованими параметрами з однаковою повільністю.

Дивність полягає в тому, що коли я беру неспіввіднесений підзапит і кидаю його в таблицю темпів, а потім використовую, що замість підзапиту, запит працює нормально. Також (і це найдивніше для мене), якщо я додаю цей фрагмент коду до кінця запиту, запит працює чудово:

and t.name like '%'

З цих маленьких експериментів я зробив висновок (можливо, неправильно), що причина уповільнення пов'язана з тим, як налаштований кешований план виконання SQL - коли запит трохи інший, він повинен створити новий план виконання.

Моє запитання таке: Коли запит, який раніше швидко запускався, раптово починає повільно працювати посеред ночі, і нічого іншого не впливає, окрім цього одного запиту, як я його усуваю і як уникнути його в майбутньому ? Звідки я можу знати, що SQL робить всередині, щоб зробити його таким повільним (якщо поганий запит запустився, я міг би отримати його план виконання, але він не запуститься - можливо, очікуваний план виконання мені щось дасть?)? Якщо ця проблема пов'язана з планом виконання, як я не можу думати SQL, що справді хитрі плани виконання - це гарна ідея?

Крім того, це не проблема з обнюхуванням параметрів. Я бачив це раніше, і це не все, тому що навіть коли я жорстко кодую вараліати в SSMS, я все ще отримую повільну продуктивність.


Чи можете ви поділитися планом запитів (повільним) тут: brentozar.com/pastetheplan
MJH

Відповіді:


31

Коли запит, який використовувався для швидкого запуску, раптом починає повільно працювати посеред ночі, і нічого іншого не впливає, окрім цього одного запиту, як я його усуваю ...?

Ви можете почати, перевіривши, чи є план виконання ще в кеші. Перевірте sys.dm_exec_query_stats, sys.dm_exec_procedure_statsі sys.dm_exec_cached_plans. Якщо план поганого виконання все ще є кешованим, ви можете проаналізувати його, а також можете перевірити статистику виконання. Статистика виконання буде містити інформацію як логічне зчитування, час процесора та час виконання. Вони можуть дати чіткі вказівки, у чому полягає проблема (наприклад, велике сканування проти блокування). Див. Розділ Визначення проблемних запитів для пояснення, як інтерпретувати дані.

Крім того, це не проблема з обнюхуванням параметрів. Я бачив це раніше, і це не все, тому що навіть коли я жорстко кодую вараліати в SSMS, я все ще отримую повільну продуктивність.

Я не переконаний. Змінні жорсткого кодування в SSMS не підтверджують, що попередній план поганого виконання не був складений проти перекошеного вводу. Будь ласка, прочитайте параметри «нюхання», «вбудовування» та параметри «РЕКОМПІЛЬ» для дуже хорошої статті з цієї теми. Повільний у програмі, швидкий у SSMS? Розуміння таємниць продуктивності - ще одна відмінна довідка.

З цих маленьких експериментів я зробив висновок (можливо, неправильно), що причина уповільнення пов'язана з тим, як налаштований кешований план виконання SQL - коли запит трохи інший, він повинен створити новий план виконання.

Це можна легко перевірити. SET STATISTICS TIME ONпокаже вам компіляцію та час виконання. SQL Server: Лічильники ефективності статистики також виявлять, чи є компіляція проблемою (чесно кажучи, я вважаю це малоймовірним).

Однак ви можете потрапити на щось подібне: ворота надання запиту. Докладніше читайте Про розуміння гранту пам'яті SQL-сервера . Якщо ваш запит вимагає великого дозволу, миттєво немає пам’яті, його доведеться почекати, і все це буде виглядати як «повільне виконання» програми. Аналіз статистики інформації про очікування виявить, чи це так.

Для більш загальної дискусії про те, що вимірювати та на що звернути увагу, див. Як аналізувати продуктивність SQL Server


7

Це поле для запуску складних запитів у SQL Server. На щастя, це трапляється не так часто.

Подивіться план запиту для запиту (коли він працює повільно). Я здогадуюсь, що ви знайдете вкладене з'єднання циклу, яке трапляється один або кілька разів на таблицях без індексів для з'єднання. Це дійсно уповільнює справи. Для швидкого переходу вперед, спосіб виправити це - з підказкою. Додайте наступне в кінці запиту:

OPTION (MERGE JOIN, HASH JOIN)

Це, як правило, вирішило цю проблему для мене в минулому.

Що може статися, це те, що незначні зміни таблиці (або наявності тимчасового простору) викликають оптимізацію SQL, щоб віддати перевагу більш повільному алгоритму приєднання. Це може бути досить тонким і досить раптовим. Коли ви створюєте тимчасову таблицю, оптимізатор має більше інформації про таблицю (наприклад, її розмір), щоб він міг генерувати кращий план.


1
План виконання дійсно використовує вкладене з'єднання циклу. Однак, коли я розміщую підказку, як ви пропонуєте, я отримую цю помилку: "Процесор запитів не міг створити план запитів через підказки, визначені в цьому запиті. Повторне подання запиту, не вказуючи жодних підказок і не використовуючи SET FORCEPLAN." Коли я додаю OPTION (LOOP JOIN), звичайно, це створить план виконання, але у мене все ще виникає проблема з повільним запуском. Ви стикалися з цим питанням? Схоже, він вважає, що НЕОБХІДНЕ потрібен цикл приєднання.

@Trevor. . . Ні, я насправді не бачив цієї проблеми. Можливо, ваш запит виконує деякі нееквіорджоїни (не використовують рівні знаки), і оптимізатору доводиться використовувати вкладені петлі.
Гордон Лінофф

3

Зазвичай це відсутній індекс, що викликає подібні проблеми.

Зазвичай я запускаю запит за допомогою SQL Management Studio і вмикаю "Включити фактичний план виконання (CTRL + M)" і з’ясовую, який приєднання має найбільший відсоток.

Додаток не фокусується на вузькому місці, але ви можете знайти його "швидко", просто вивчивши результат.

Приклад тут: 48PercentForTop


2
індекс несподівано не зникне "не вистачає", тому, хоча це може покращити продуктивність, це не пояснить проблему
Fowl

3

Нещодавно я пережив це саме питання, яке привело мене до цієї сторінки.

@MartinSmith щось дотримувався, коли рекомендував оновити статистику та пояснити план. Хочу додати, що вам слід також спробувати переконатися, що ви переглядаєте запущені завдання / запити, які можуть створювати блокування і тим самим сповільнювати час відповіді.

У моєму випадку винуватець став статистикою таблиці збору робочих місць. Чомусь він не заповнився у вікні, яке він мав, і продовжував працювати, коли користувачі відновили. Я знайшов процес, вбив його, і запити знову почали відповідати.

Я сподіваюся, що це допомагає комусь іншому


0

Вам також потрібно перевірити, чи запущено будь-яке резервне копіювання сервера чи якісь завдання архівації \ індексації, коли ви бачите проблеми з продуктивністю в T-SQL \ Процедурі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.