Когда sp_executesql обновляет план запроса?

13

Вы должны простить мою наивность, поскольку я не администратор баз данных, но, насколько я понимаю, со временем статистика изменения базы данных и хранимая процедура должны быть перекомпилированы, чтобы поддерживать план запроса в актуальном состоянии с учетом последних статистических данных.

Предполагая, что у меня есть хранимая процедура в моей базе данных, которая перекомпилируется с последней статистикой через некоторый регулярный интервал, каковы последствия включения хранимой процедуры в код и ее переноса в sp_executesqlоператор? Потеряю ли я обновление плана запроса, который раньше выполнялся как часть перекомпиляции процедуры?

Если есть что-то еще (кроме разрешений), которое мне нужно рассмотреть, прежде чем я сделаю это изменение, я буду признателен за ваши идеи.

Я прочитал это на MSDN:

Способность оптимизатора запросов SQL Server сопоставлять новую строку Transact-SQL с существующим планом выполнения ограничивается постоянно меняющимися значениями параметров в тексте строки, особенно в сложных операторах Transact-SQL.

Итак, если предположить, что хранимая процедура, которую я пытаюсь встроить и встроить sp_executesql, действительно содержит некоторые параметры, означает ли это, что, хотя мой план выполнения кэшируется, я затрудняю его обнаружение и повторное использование SQL Server?

Джеймс Льюис
источник

Ответы:

7

Строка из MSDN говорит об использовании EXEC(), как это:

SET @sql = 'SELECT foo FROM dbo.bar WHERE x = ''' + @x + ''';';
EXEC(@sql);

В моем тестировании современные версии SQL Server все еще могут повторно использовать план, подобный этому, но могут быть и другие переменные (например, версия или, например, если вы добавляете условные выражения). WHERE предложения, основанные на наличии определенных параметров, - в этом случае это будет генерировать другой план).

Если вы используете sp_executesqlего, значения параметров могут все еще вызывать проблемы с анализом параметров (как и в обычном SQL), но это не имеет ничего общего с тем, может ли SQL Server повторно использовать план. Этот план будет использоваться снова и снова, как если бы вы его не использовали sp_executesqlвообще, если только переменные, которые могут вызвать перекомпиляцию прямого запроса, в этом случае этот тоже будет перекомпилирован (по сути, SQL Server не сохранить что-нибудь с планом, который говорит: «это было выполнено из sp_executesql, но это не было):

SET @sql = N'SELECT foo FROM dbo.bar WHERE x = @x;';
EXEC sp_executesql @sql, N'@x VARCHAR(32)', @x;

В качестве бонуса, он имеет встроенную защиту от динамического SQL и избавляет от необходимости беспокоиться об удвоении одинарных кавычек из-за разделителей строк. Я писал о некоторых из этого здесь .

Если у вас возникли проблемы с планом повторного использования и / или параметр нюхают, некоторые вещи , которые вы должны смотреть на это OPTION (RECOMPILE), OPTIMIZE FOR, optimize for ad hoc workloadsи simple/forced parameterization. Я ответил на несколько похожих вопросов в ответ на недавнюю веб-трансляцию здесь, возможно, стоит снять:

http://sqlperformance.com/performance-palooza

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

Аарон Бертран
источник
2

Запросы, выполняемые через sp_executesql, следуют тем же правилам планов выполнения, что и обычные запросы, которые не выполняются через sp_executesql. Если текст запроса изменяется, создается новый план. Если текст не изменяется из-за пользователя параметров, то план используется повторно. Когда статистика обновляется, планы истекают, и новые планы генерируются при следующем запуске запроса.

mrdenny
источник
Спасибо за ваш ответ, я внес изменения в параметры, поскольку теперь я понял, что каждый раз, когда я вызываю sp_ExecuteSql, я буду использовать в качестве запроса другую строку из-за того факта, что с точки зрения Sql Server я заменил параметры с жестко закодированными значениями (они будут введены в код, прежде чем я отправлю свой запрос на Sql Server). Вы знаете способ обойти это? Поможет ли объявление переменных в моем встроенном выражении sql оптимизатору запросов найти мой кэшированный план запросов?
Джеймс Льюис