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