Оптимизация запросов SQL Server: где (Col = @ Col или @ Col = Null) - PullRequest
3 голосов
/ 20 декабря 2009

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

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

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-5 раз медленнее, чем если бы я заменил предложение where на:

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

Я еще больше озадачен тем фактом, что замена нуля на -1 дает мне почти ту же скорость, что и в приведенном выше «фиксированном» предложении WHERE:

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. Это может быть связано (или фактически может быть) с проблемой перехвата параметров Анализ параметров (или спуфинг) в SQL Server Для чего бы это ни стоило, я был тестирование почти исключительно с "exec SomeProc" после каждого редактировать / перекомпилировать процесс, т.е. необязательный параметр не указан.

1 Ответ

6 голосов
/ 20 декабря 2009

У вас комбинация проблем, скорее всего

  1. Параметр сниффинг
  2. ИЛИ не является хорошим оператором для использования

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

Параметр сниффинг

... по умолчанию "NULL". Попробуйте сделать это с другими значениями по умолчанию, скажем, -1 или нет по умолчанию.

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

Вы также можете попробовать ОПТИМИЗИРОВАТЬ ДЛЯ НЕИЗВЕСТНЫХ в 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
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...