У меня есть оператор удаления, который использует неверный план при запуске внутри хранимой процедуры, но выбирает гораздо лучший план при запуске ad-hoc.
Я перестроил все индексы для таблиц, используемых запросом, и удалил все кэши. Оптимизатор по-прежнему выбирает неправильный план для хранимой процедуры.
Я хотел бы знать, почему оптимизатор использует другой план выполнения для хранимой процедуры в отличие от специального SQL.
ОБНОВЛЕНИЕ: я думаю, что это, должно быть, параметры в конце концов - когда я запустил специальный код с жестко закодированной переменной, я могу получить «плохой» план с правильным значением (это дата, значения, которые годичны похоже на генерацию "хорошего" плана). Теперь перейдем к попытке навязать «хороший» план процессу с помощью подсказки запроса.
РЕШЕНИЕ: я получил план, который хотел, используя подсказку ОПТИМИЗАЦИЯ ДЛЯ НЕИЗВЕСТНОГО.
источник
WHERE
предложении?Ответы:
Обычные подозреваемые:
Точка 1: оптимизатор может выбрать лучший план для констант.
Изменить константы = изменить план. Параметризованный плен можно восстановить
Точка 2 вводит неявные преобразования из-за приоритета типа данных,
например столбец varchar по сравнению с параметром nvarchar
Точка 3: используйте маскировку параметров или OPTIMIZE FOR UNKNOWN.
Редактирование: Для проверки: запустите сохраненный процесс, запустите sp_updatestats, запустите снова. Это сделает недействительными кэшированные планы, что лучше, чем очистка кэша планов
Изменить: после комментария jcolebrand
Вы можете отключить сниффинг несколькими способами. Основными 3 являются
Маскировка параметров:
Маскировка и подсказка ОПТИМИЗАЦИЯ имеют одинаковый эффект (возможно, по разным причинам). То есть оптимизатор должен использовать статистику и распределение данных ( Примечание: все еще тестируется Марком Стори-Смитом ), чтобы
оценить параметры по их собственным достоинствам ?, а не то, что они были в последний раз. Оптимизатор может перекомпилировать или нет. В SQL Server 2005 добавлена перекомпиляция на уровне операторов, чтобы уменьшить влияниеТеперь, почему план с «вынюхиваемыми» параметрами является «липким» по сравнению с замаскированными / «неизвестными» параметрами, я не уверен.
Я использовал маскирование параметров начиная с SQL Server 2000 для всего, кроме самого простого кода. Я заметил, что это может произойти с более сложным кодом. А на моей старой работе у меня есть несколько процедур отчетов, которые я могу изменить по умолчанию для параметров плана. Я считаю, что подход "культа груза" был проще, чем звонок в службу поддержки.
Изменить 2, 12 октября 2011, после некоторого чата
Насколько я могу судить, маскирование параметров и ОПТИМИЗАЦИЯ ДЛЯ НЕИЗВЕСТНО имеют тот же эффект
. Подсказка более чистая, чем маскировка, но была добавлена в SQL Server 2008.
Обнаружение параметров происходит во время компиляции.
С RECOMPILE генерирует новый план при каждом выполнении. Это означает, что плохой выбор значений по умолчанию повлияет на план. На моей последней работе я мог легко продемонстрировать это с помощью некоторого кода отчета: изменение параметров по умолчанию изменило план независимо от предоставленных параметров.
Эта статья о MS Connect интересна: субоптимальное использование индекса в хранимой процедуре (упомянуто в одном из ответов SO ниже)
Нерешенные вопросы
Применяется ли сниффинг с RECOMPILE? То есть, если оптимизатор знает, что отказаться от плана, он стремится к повторному использованию?
Почему обнюхиваемые планы "липкие"?
Ссылки с SO:
https://stackoverflow.com/q/272726/27535
Ремус Русану (команда MS SQL) и я устроили драку здесь на SO
источник
OPTION (RECOMPILE)
или весь процесс,WITH RECOMPILE
чтобы заставить SQL Server игнорировать существующие планы.OPTIMIZE
, потому что Microsoft - американская компания. :)Не забывайте, что настройки ANSI, которые вы настроили для плана соединений, играют роль в выборе плана выполнения. Когда приложение вызывает хранимую процедуру, оно, вероятно, имеет другие настройки ANSI, чем ваше соединение SSMS.
источник