Возможно, вы захотите посмотреть ответ на этот похожий вопрос здесь:
/programming/11329823/add-where-clauses-to-sql-dynamically-programmatics
Мы обнаружили, что SPROC принимает множество необязательных параметров и реализует фильтр следующим образом:
CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS
...
SELECT field1, field2, ... FROM [Table]
WHERE
(@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)
будет кешировать первый план выполнения, с которым он запускается (например @optionalParam1 = 'Hello World', @optionalParam2 = NULL
), но затем выполнится с треском, если мы передадим ему другой набор необязательных параметров (например @optionalParam1 = NULL, @optionalParam2 = 42
). (И, очевидно, мы хотим, чтобы производительность кэшированного плана, так WITH RECOMPILE
что нет)
Исключением здесь является то, что если в запросе также есть хотя бы один ОБЯЗАТЕЛЬНЫЙ фильтр, который ВЫСОКО селективен и правильно проиндексирован, в дополнение к необязательным параметрам, то вышеупомянутый PROC будет работать нормально.
Однако, если ВСЕ фильтры являются необязательными, довольно ужасная истина заключается в том, что параметризованный динамический sql действительно работает лучше (если вы не напишите N! Различных статических PROCS для каждой перестановки необязательных параметров).
Динамический SQL, подобный приведенному ниже, будет создавать и кэшировать отдельный план для каждой перестановки параметров запроса, но по крайней мере каждый план будет «адаптирован» для конкретного запроса (не имеет значения, является ли он PROC или Adhoc SQL - как Пока они являются параметризованными запросами, они будут кэшироваться)
Поэтому отсюда мое предпочтение:
DECLARE @SQL NVARCHAR(MAX)
-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'
IF @OptionalParam1 IS NOT NULL
BEGIN
SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'
END
IF @OptionalParam2 IS NOT NULL
BEGIN
SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'
END
EXEC sp_executesql @SQL,
N'@optionalParam1 NVARCHAR(50),
@optionalParam2 INT'
,@optionalParam1 = @optionalParam1
,@optionalParam2 = @optionalParam2
и т.д. Неважно, если мы передадим избыточные параметры в sp_executesql - они игнорируются. Стоит отметить, что ORM, такие как Linq2SQL и EF, используют параметризованный динамический sql аналогичным образом.