2009-12-20 5 views
3

Не знаете, с чего начать с этого - не уверен, что проблема в том, что я обманываю оптимизатор запросов, или если это что-то внутреннее к способу работы индексов, когда задействованы нули.Оптимизация запросов SQL Server: где (Col = @ Col или @ Col = Null)

Одно кодирования конвенции я следовал, чтобы кодировать хранимые процедуры, как, например:

declare procedure SomeProc 
    @ID int = null 
as 
    select 
    st.ID,st.Col1,st.Col2 
    from 
    SomeTable st 
    where 
    (st.ID = @ID or @ID is null) --works, but very slow (relatively) 

Не очень полезно в этом простом тесте, конечно, но полезные в других сценариях, когда вы хотите, хранимую процедуру для действовать либо по всей таблице, либо по строкам, удовлетворяющим некоторым критериям. Тем не менее, это довольно медленно при использовании на больших столах ... примерно 3-5x медленнее, чем если бы я заменил, где положение с:

where 
    st.ID = @ID --3-5x faster than first example 

Я еще озадачен тем фактом, что заменяющий нуль с -1 дает мне почти такую ​​же скорость, что и «фиксированный» ИНЕКЕ выше:

declare procedure SomeProc 
    @ID int = -1 
as 
    select 
    st.ID,st.Col1,st.Col2 
    from 
    SomeTable st 
    where 
    (st.ID = @ID or @ID=-1) --much better... but why? 

Очевидно, что это нулевая, что делает вещи дурацкие, но почему именно? Ответ на это не ясен, когда я рассматриваю план исполнения. Это то, что я заметил на протяжении многих лет в различных базах данных, таблицах и выпусках SQL Server, поэтому я не думаю, что это причуда моей текущей среды. Я решил проблему, переключив значение параметра по умолчанию от нуля до -1; мой вопрос почему это работает.

Примечания

  1. SomeTable.ID индексируется
  2. Это может быть связано с (или может, на самом деле, быть) параметр нюхают вопрос Parameter Sniffing (or Spoofing) in SQL Server За то, что он стоит, я был тестирование почти исключительно с «exec SomeProc» после каждого редактирование/перекомпиляция proc, т. Е. С необязательный параметр опущен.

ответ

6

У вас есть сочетание вопросов, скорее всего,

  1. нюхают параметров
  2. OR не является хорошим оператором, чтобы использовать

Но не видя планы, эти образованные предположения ,

Параметр нюхать

... из "NULL" по умолчанию. Попробуйте с разными значениями по умолчанию, например, -1 или нет по умолчанию.

@ID = -1 с по умолчанию NULL и параметром sniffing = тривиальная проверка, так что это быстрее.

Вы также можете попробовать OPTIMISE FOR UNKNOWN в SQL Server 2008

оператора ИЛИ

Некоторые идеи ..

Если столбцы не обнуляемые, в большинстве случаев Оптимизатор игнорирует условие

st.ID = ISNULL(@ID, st.ID) 

Кроме того, вы можете использовать IF заявления

IF @ID IS NULL 
    SELECT ... FROM... 
ELSE 
    SELECT ... FROM... WHERE st.ID 

Или UNION ALL аналогичным образом.

Лично я хотел бы использовать параметр маскирования (всегда) и ISNULL в большинстве случаев (я бы попробовать его первым)

alter procedure SomeProc 
    @ID int = NULL 
AS 
declare @maskID int 
select @maskID = @ID 
... 
+0

Спасибо большое за ответ. Я подозреваю, что это было больше всего. Я был довольно не осведомлен о том, насколько дорого или может быть. В конце концов, после вашей реплики, я пошел с SET @ ID = ISNULL (@ ID, -1) в верхней части сохраненного proc для удобства чтения. (Фактическая сохраненная процедура довольно длинная, и я не хочу похоронить «по умолчанию» глубоко внутри. Спасибо еще раз. –

Смежные вопросы