Параметр Sniffing (или Spoofing) в SQL Server
Некоторое время назад у меня был запрос, который я использовал довольно много для одного из моих пользователей. Он все еще эволюционировал и настраивался, но в итоге он был стабилизирован и работал довольно быстро, поэтому мы создали из него хранимую процедуру.
До сих пор такой нормальный.
Однако хранимая процедура была медленной. Нет существенной разницы между запросом и proc, но изменение скорости было массивным.
[Фон, мы запускаем SQL Server 2005.]
Дружественный локальный администратор баз данных (который больше не работает здесь) рассмотрел хранимую процедуру и сказал, что "спуфинг параметров!" ( Изменить:, хотя кажется, что он, возможно, также известен как "обнюхивание параметров", что может объяснить нехватку хитов Google, когда я пытался его найти.)
Мы отвлекли часть хранимой процедуры ко второму, завернули вызов этого нового внутреннего proc в ранее существовавший внешний, называемый внешним, и, hey presto, он был так же быстро, как исходный запрос.
Итак, что дает? Может ли кто-то объяснить параметризацию спуфинга?
Бонусный кредит для
- подчеркивание того, как его избежать
- предлагая, как распознать возможную причину.
- обсуждать альтернативные стратегии, например. статистика, индексы, ключи, для смягчения ситуации.
Ответы
Ответ 1
FYI - вам нужно знать что-то еще, когда вы работаете с SQL 2005 и сохраняете procs с параметрами.
SQL Server будет компилировать сохраненный план выполнения процесса с использованием первого параметра. Поэтому, если вы запустите это:
usp_QueryMyDataByState 'Rhode Island'
План выполнения будет работать лучше всего с небольшими данными состояния. Но если кто-то оборачивается и бежит:
usp_QueryMyDataByState 'Texas'
План выполнения, предназначенный для данных по размеру на острове Род-Айленд, может быть не столь эффективным с данными по размеру в Техасе. Это может привести к неожиданным результатам при перезапуске сервера, поскольку вновь созданный план выполнения будет нацелен на любой параметр, который будет использоваться первым - не обязательно лучший. План не будет перекомпилирован до тех пор, пока не будет большой причины для этого, например, если статистика будет восстановлена.
Здесь возникают планы запросов, и SQL Server 2008 предлагает множество новых функций, которые помогают администраторам баз данных выстраивать определенный план запросов в долгосрочной перспективе независимо от того, какие параметры вызывают в первую очередь.
Моя забота заключается в том, что когда вы перестроили свою сохраненную proc, вы заставили план выполнения перекомпилировать. Вы назвали его своим любимым параметром, и тогда, конечно, это было быстро - но проблема, возможно, не была сохраненной процедурой. Возможно, что сохраненная процедура была перекомпилирована в какой-то момент с необычным набором параметров и, следовательно, неэффективным планом запросов. Возможно, вы ничего не исправили, и вы можете столкнуться с такой же проблемой при следующем перезапуске сервера или повторном компиляции плана запроса.
Ответ 2
Да, я думаю, вы имеете в виду параметр sniffing, который используется оптимизатором SQL Server, чтобы попытаться определить значения/диапазоны параметров, чтобы он мог выбрать лучший план выполнения для вашего запроса. В некоторых случаях SQL Server выполняет небольшую работу по параметру sniffing и не выбирает лучший план выполнения для запроса.
Я считаю, что эта статья в блоге http://blogs.msdn.com/queryoptteam/archive/2006/03/31/565991.aspx имеет хорошее объяснение.
Кажется, что DBA в вашем примере выбрал опцию # 4, чтобы переместить запрос в другой sproc в отдельный процедурный контекст.
Вы также могли бы использовать перекомпилировать исходный sproc или использовать параметр optimize for для параметра.
Ответ 3
Простым способом ускорения этого является переназначение входных параметров локальным параметрам в самом начале sproc, например
CREATE PROCEDURE uspParameterSniffingAvoidance
@SniffedFormalParameter int
AS
BEGIN
DECLARE @SniffAvoidingLocalParameter int
SET @SniffAvoidingLocalParameter = @SniffedFormalParameter
--Work w/ @SniffAvoidingLocalParameter in sproc body
-- ...
Ответ 4
Параметр sniffing - это метод, который SQL Server использует для оптимизации плана выполнения запросов для хранимой процедуры. Когда вы сначала вызываете хранимую процедуру, SQL Server просматривает заданные значения параметров вашего вызова и решает, какие индексы использовать на основе значений параметров.
Поэтому, когда первый вызов содержит не очень типичные параметры, SQL Server может выбирать и хранить не оптимальный план выполнения в отношении следующих вызовов хранимой процедуры.
Вы можете обойти это с помощью
- с помощью
WITH RECOMPILE
- копирование значений параметров в локальные переменные внутри хранимой процедуры и использование локалей в ваших запросах.
Я даже слышал, что лучше вообще не использовать хранимые процедуры, кроме как отправлять запросы непосредственно на сервер.
Недавно я столкнулся с той же проблемой, в которой у меня пока нет реального решения.
Для некоторых запросов копия на локальные вары помогает вернуться к правильному плану выполнения, поскольку некоторые запросы производительности ухудшаются с локальными варами.
Мне еще нужно сделать больше исследований о том, как SQL Server кэширует и повторно использует (субоптимальные) планы выполнения.
Ответ 5
По моему опыту лучшим решением для sniffing параметра является "Dynamic SQL". Следует отметить две важные вещи: 1. вы должны использовать параметры в своем динамическом sql-запросе 2. вы должны использовать sp_executesql (а не sp_execute), который сохраняет план выполнения для каждого значения параметра
Ответ 6
У меня была аналогичная проблема. Мой план выполнения хранимой процедуры занял 30-40 секунд. Я попытался использовать SP-запросы в окне запроса, и для выполнения этого потребовалось несколько мс.
Затем я разработал объявление локальных переменных в хранимой процедуре и передачу значений параметров локальным переменным. Это сделало выполнение SP очень быстрым, и теперь тот же самый SP выполняется в течение нескольких миллисекунд вместо 30-40 секунд.
Ответ 7
Очень простой и сортированный, оптимизатор запросов использует старый план запросов для часто выполняемых запросов. но на самом деле размер данных также увеличивается, поэтому в то время требуется новый оптимизированный план и все еще оптимизатор запросов, используя старый план запроса. Это называется параметром Sniffing.
Я также создал подробный пост по этому вопросу. Пожалуйста, посетите этот URL:
http://www.dbrnd.com/2015/05/sql-server-parameter-sniffing/
Ответ 8
Изменение вашей процедуры хранения для выполнения в виде пакета должно увеличить скорость.
Выбор пакетного файла, а именно:
exec ('select * from order where order id ='''+ @ordersID')
Вместо обычной хранимой процедуры выберите:
select * from order where order id = @ordersID
Просто введите параметр nvarchar
и вы получите более быстрые результаты.