Использование синтаксиса, подобного (@Dispid IS NULL OR dispid = @Dispid )
в WHERE
, может иметь серьезные последствия для производительности. Это связано с тем, что SQL Server будет кэшировать план запроса на основе первого запуска оператора. Это означает, что если @DispID
имеет значение, отличное от NULL
, то при передаче значения NULL
план запроса будет сильно занижать количество строк в запросе.
Следовательно, существует 2опции, которые вы можете использовать, чтобы избежать неправильного кэширования плана запроса;однако я считаю, что первое не существует в полностью неподдерживаемой версии 2008 года .
Первое (примечание, предостережение) использует OPTION RECOMPILE
;что заставляет план запроса воссоздавать каждый раз при выполнении запроса. Это легче написать, однако, доза достигается за счет отсутствия кэширования плана:
SELECT ...
FROM ...
WHERE Cancelled = 0
AND (@Dispid IS NULL OR dispid = @Dispid)
OPTION (RECOMPILE);
Второй - использовать динамическое выражение:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET @SQL = N'SELECT Column1,' + @CRLF +
N' ...,' + @CRLF + --....etc
N'FROM ...' + @CRLF +
N'WHERE Cancelled = 0' +
CASE WHEN @DispID IS NOT NULL THEN @CRLF + N' AND DispID = @Disp' ELSE N'' END + N';'
EXEC sp_executesql @SQL, N'@DispID int', @DispID; --@DispID data type guessed
Это имеетПреимущество в том, что разные операторы будут иметь разные кэшированные планы, и их не нужно каждый раз пересматривать, однако для некоторых это не так легко понять.
Гейл Шоу и Аарон Бертран написал обе статьи по этим Catch-All (или "Kitchen Sink") запросам, которые обеспечат хорошее бесплатное чтение.