Convém consultar a resposta para esta pergunta semelhante aqui:
/programming/11329823/add-where-clauses-to-sql-dynamically-programmatically
Descobrimos que um SPROC que utiliza vários parâmetros opcionais e implementa o filtro da seguinte maneira:
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)
armazenará em cache o primeiro plano de execução com o qual é executado (por exemplo @optionalParam1 = 'Hello World', @optionalParam2 = NULL
), mas executará miseravelmente se passarmos a ele um conjunto diferente de parâmetros opcionais (por exemplo @optionalParam1 = NULL, @optionalParam2 = 42
). (E, obviamente, queremos o desempenho do plano em cache, então WITH RECOMPILE
está fora)
A exceção aqui é que, se houver TAMBÉM pelo menos um filtro OBRIGATÓRIO na consulta que seja ALTAMENTE seletivo e indexado adequadamente, além dos parâmetros opcionais, o PROC acima funcionará bem.
No entanto, se TODOS os filtros forem opcionais, a terrível verdade é que o sql dinâmico parametrizado realmente funciona melhor (a menos que você escreva N! PROCS estático diferente para cada permutação de parâmetros opcionais).
SQL dinâmico como o abaixo criará e armazenará em cache um plano diferente para cada permutação dos parâmetros de consulta, mas pelo menos cada plano será 'adaptado' à consulta específica (não importa se é um PROC ou Adhoc SQL - como desde que sejam consultas parametrizadas, elas serão armazenadas em cache)
Portanto, portanto, minha preferência por:
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
etc. Não importa se passamos parâmetros redundantes para sp_executesql - eles são ignorados. Vale ressaltar que ORMs como Linq2SQL e EF usam sql dinâmico parametrizado de maneira semelhante.