Обнаружение параметров (или спуфинг) в SQL Server - PullRequest
63 голосов
/ 17 октября 2008

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

Пока все нормально.

Тем не менее, хранимая процедура была медленной. Нет существенной разницы между запросом и процедурой, но изменение скорости было огромным.

[Справочная информация, мы запускаем SQL Server 2005.]

Дружественный локальный администратор баз данных (который здесь больше не работает) взглянул на хранимую процедуру и сказал: «Подмена параметров!» ( Редактировать: , хотя, возможно, он также известен как «сниффинг параметров», что может объяснить нехватку хитов Google, когда я пытался его найти.)

Мы абстрагировали некоторую хранимую процедуру ко второй, обернули вызов этого нового внутреннего процесса в существовавший ранее внешний, называемый внешним, и, эй presto, это было так же быстро, как исходный запрос.

Итак, что дает? Может кто-нибудь объяснить подделку параметров?

Бонусный кредит на

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

Ответы [ 8 ]

53 голосов
/ 19 октября 2008

К вашему сведению - вам нужно знать что-то еще, когда вы работаете с SQL 2005 и храните процы с параметрами.

SQL Server скомпилирует план выполнения хранимой процедуры с первым используемым параметром. Так что, если вы запустите это:

usp_QueryMyDataByState 'Rhode Island'

План выполнения будет лучше всего работать с данными небольшого штата. Но если кто-то оборачивается и бежит:

usp_QueryMyDataByState 'Texas'

План выполнения, разработанный для данных размером с Род-Айленд, может быть не таким эффективным с данными размером с Техас. Это может привести к неожиданным результатам при перезапуске сервера, поскольку вновь созданный план выполнения будет нацелен на любой параметр, который используется первым - не обязательно лучший. План не будет перекомпилирован, пока не будет серьезной причины для этого, например, если статистика будет перестроена.

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

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

26 голосов
/ 17 октября 2008

Да, я думаю, вы имеете в виду анализ параметров, который является техникой, которую оптимизатор SQL Server использует для определения значений / диапазонов параметров, чтобы он мог выбрать наилучший план выполнения для вашего запроса. В некоторых случаях SQL Server плохо выполняет анализ параметров и не выбирает лучший план выполнения для запроса.

Я считаю, что эта статья блога http://blogs.msdn.com/queryoptteam/archive/2006/03/31/565991.aspx имеет хорошее объяснение.

Похоже, что администратор БД в вашем примере выбрал вариант # 4, чтобы переместить запрос в другой sproc в отдельный процедурный контекст.

Вы могли также использовать с перекомпиляцией на исходном sproc или использовать опцию optimize для для параметра.

24 голосов
/ 19 октября 2008

Простой способ ускорить это - переназначить входные параметры локальным параметрам в самом начале процесса, например,

CREATE PROCEDURE uspParameterSniffingAvoidance
    @SniffedFormalParameter int
AS
BEGIN

    DECLARE @SniffAvoidingLocalParameter int
    SET @SniffAvoidingLocalParameter = @SniffedFormalParameter

    --Work w/ @SniffAvoidingLocalParameter in sproc body 
    -- ...
4 голосов
/ 09 ноября 2010

По моему опыту, лучшим решением для анализа параметров является «Динамический SQL». Следует отметить две важные вещи: 1. вы должны использовать параметры в динамическом sql-запросе 2. вы должны использовать sp_executesql (а не sp_execute), который сохраняет план выполнения для каждого значения параметра

4 голосов
/ 22 октября 2008

Анализ параметров - это метод, который SQL Server использует для оптимизации плана выполнения запроса для хранимой процедуры. При первом вызове хранимой процедуры SQL Server просматривает заданные значения параметров вашего вызова и решает, какие индексы использовать, основываясь на значениях параметров.

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

Вы можете обойти это, либо

  • с использованием WITH RECOMPILE
  • копирование значений параметров в локальные переменные внутри хранимой процедуры и использование локальных переменных в ваших запросах.

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

Мне все еще нужно больше исследовать, как SQL Server кэширует и повторно использует (неоптимальные) планы выполнения.

0 голосов
/ 21 августа 2015

Очень просто и удобно. Оптимизатор запросов использует старый план запросов для часто выполняемых запросов. но на самом деле размер данных также увеличивается, поэтому в это время требуется новый оптимизированный план и все еще оптимизатор запросов, использующий старый план запроса. Это называется параметрическим анализом. Я также создал подробный пост по этому вопросу. Пожалуйста, посетите этот URL: http://www.dbrnd.com/2015/05/sql-server-parameter-sniffing/

0 голосов
/ 26 марта 2013

У меня была похожая проблема. План выполнения моей хранимой процедуры занял 30-40 секунд. Я попытался использовать операторы SP в окне запроса, и это заняло несколько мс. Затем я разработал объявление локальных переменных в хранимой процедуре и передачу значений параметров локальным переменным. Это сделало выполнение SP очень быстрым, и теперь тот же SP выполняется в течение нескольких миллисекунд вместо 30-40 секунд.

0 голосов
/ 17 июля 2012

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

Выбор пакетного файла, т. Е.

exec ('select * from order where  order id ='''+ @ordersID')

Вместо обычной хранимой процедуры выберите:

select * from order where  order id = @ordersID

Просто передайте параметр как nvarchar, и вы получите более быстрые результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...