Раптом повільний план виконання для збереженої програми


15

Я намагаюся зрозуміти проблему, яку ми маємо з SQL Server 2000. Ми є веб-сайтом з помірною трансакцією, і у нас є збережена програма, sp_GetCurrentTransactionsяка називається, яка приймає ID клієнта та дві дати.

Тепер, залежно від дат та замовника, цей запит може повернути що-небудь від нуля до 1000-ти рядків.

Проблема: те, що ми пережили, полягає в тому, що раптом ми отримаємо ряд помилок (як правило, Execution Timeout Expiredабо подібних) для конкретного клієнта, коли вони намагаються виконати цей збережений процес. Тож ми вивчаємо запит, запускаємо його в SSMS і виявляємо, що він займає 30 років. Таким чином, ми перекомпілюємо збережені proc і -bang- він працює зараз через 300 мс.

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

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

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

Будь-які відповіді високо оцінені.


чи є твердження if / else в proc? Я бачив, що це відбувається, коли план кешується в операторі if, а потім намагається виконати під блоком else, використовуючи неправильний план. Чи відповідали ці помилки зміною проц?
Джеремі Грей

@Jeremy: Жодних змін у proc і не більше / if операторах.
Ciaran Archer

Відповіді:


14

Ця проблема називається нюханням параметрів.

Більш пізні версії SQL Server дають вам більше варіантів впоратися з ним, наприклад, OPTION (RECOMPILE)або OPTIMIZE FORпідказки.

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

Зазвичай найбільш катастрофічно погані плани складаються з параметрів, що мають дуже високу вибірковість, але мають параметри з низькою селективністю.

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

Недоліком є ​​те, що для деяких виконань час виконання може бути більшим, ніж для плану, розробленого спеціально для цих значень параметрів, тому це компроміс часу компіляції проти часу виконання.


3
Або "прив’язати зазирнути" в термінології Oracle
Гай

Дякую @Gaius, добре знати термінологію для декількох RDBMS;)
Андрій Ронеа

6

Замість того, щоб використовувати динамічний SQL, ви завжди можете просто змінити свої виклики на:

EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE

Ці WITH RECOMPILEсили ( як ви вже здогадалися!) Перекомпіляція плану виконання , коли вона виконується.

Ви також можете включити WITH RECOMPILEу визначення збереженого proc:

CREATE PROCEDURE usp.MyProcedure (Parameters)
WITH RECOMPILE
AS
...

2

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

Методика така - розбийте збережену процедуру на 2, один призначений для одного набору параметрів, один для іншого. Додайте до кожного пункту пункти, щоб між ними були охоплені всі можливі випадки. Подивіться плани запитів - один повинен бути оптимізований для одного набору параметрів, інший для іншого набору. Можливо, вам доведеться поцікавитись запитом, щоб це сталося, або цього неможливо досягти для вашого запиту, і в такому випадку такий підхід не буде працювати.

Тепер зробіть свою первісну збережену процедуру перевірити значення параметрів та відправте відповідну одну з двох збережених процедур з попереднього пункту.

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


1

Ви також можете спробувати SET FORCEPLANпідказки та індекси.

http://msdn.microsoft.com/en-us/library/ms188344.aspx
Це в основному дозволяє вибрати, в якому порядку відбувається приєднання.

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


0

Гммм ... якщо ми зосереджені саме на цій збереженій процедурі, я би здивувався, що використання кешованого плану виконання спричинить проблему, яку ви бачите. Я б попросив переглянути план виконання збереженої процедури з використанням набору параметрів для клієнта та двох дат. Цікаво, чи корисний би більш конкретний індекс -> такий, як у customerId, і лише дві дати?


2
Чому сюрприз? нюхання параметрів є досить поширеною проблемою з цими симптомами, і схоже, що DBA визначила це проблемою.
Мартін Сміт

@MartinSmith - Я трохи здивований, що DBA, який знає про нюхання параметрами, не знає про натяки на перекомпіляцію ...
JNK

@JNK - Це правда. Не знаю, чому вони цього не згадають.
Мартін Сміт

0

Раптом погіршення продуктивності звучить як неефективний план запитів, який створюється, ймовірно, внаслідок відсутньої статистики. Запустіть профайлер SQL Server із встановленими категоріями подій "Помилки та попередження" та перевірте, чи є попередження про відсутність статистики.

Можливо, вам також не вистачає індексу або вам може знадобитися дефрагментація індексів, оскільки вони можуть бути занадто фрагментовані для використання SQL Server, внаслідок чого думка про те, що сканування таблиці видасть менше вводу / виводу.

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

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

Отже, підсумовуючи:

  1. Перевірте відсутні статистичні дані
  2. Перевірте фрагментацію індексу
  3. Створіть і використовуйте збережену програму
  4. Будь ласка, перейменуйте proc - sp_ - це м'яко зарезервований простір імен для префіксів для внутрішніх системних систем SQL Server - в результаті SQL Server завжди завжди шукає основну базу даних для цих збережених процедур. Перейменування proc usp_ замість sp_ призведе до підвищення продуктивності, але я сумніваюсь у його вашій проблемі в цьому випадку.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.