Esse padrão
column = @argument OR (@argument IS NULL AND column IS NULL)
pode ser substituído por
EXISTS (SELECT column INTERSECT SELECT @argument)
Isso permitirá que você combine um NULL com um NULL e permitirá que o mecanismo use um índice com columneficiência. Para uma excelente análise detalhada dessa técnica, refiro-lhe o artigo do blog de Paul White:
Como existem dois argumentos no seu caso em particular, você pode usar a mesma técnica de correspondência com @Blah- dessa forma, você poderá reescrever a cláusula WHERE inteira de forma mais ou menos concisa:
WHERE
EXISTS (SELECT a.Blah, a.VersionId INTERSECT SELECT @Blah, @VersionId)
Isso funcionará rapidamente com um índice ativado (a.Blah, a.VersionId).
Ou o otimizador de consulta torna essencialmente o mesmo?
Nesse caso sim. Em todas as versões (pelo menos) do SQL Server 2005 em diante, o otimizador pode reconhecer o padrão col = @var OR (@var IS NULL AND col IS NULL)e substituí-lo pela IScomparação adequada . Isso depende da correspondência de reescrita interna; portanto, pode haver casos mais complexos em que isso nem sempre é confiável.
Nas versões do SQL Server de 2008 SP1 CU5 inclusive , você também tem a opção de usar a Otimização de incorporação de parâmetros via OPTION (RECOMPILE), na qual o valor de tempo de execução de qualquer parâmetro ou variável é incorporado na consulta como um literal antes da compilação.
Portanto, pelo menos em grande parte, nesse caso, a escolha é uma questão de estilo, embora a INTERSECTconstrução seja inegavelmente compacta e elegante.
Os exemplos a seguir mostram o 'mesmo' plano de execução para cada variação (excluídas as referências literais versus as variáveis):
DECLARE @T AS table
(
c1 integer NULL,
c2 integer NULL,
c3 integer NULL
UNIQUE CLUSTERED (c1, c2)
);
-- Some data
INSERT @T
(c1, c2, c3)
SELECT 1, 1, 1 UNION ALL
SELECT 2, 2, 2 UNION ALL
SELECT NULL, NULL, NULL UNION ALL
SELECT 3, 3, 3;
-- Filtering conditions
DECLARE
@c1 integer,
@c2 integer;
SELECT
@c1 = NULL,
@c2 = NULL;
-- Writing the NULL-handling out explicitly
SELECT *
FROM @T AS T
WHERE
(
T.c1 = @c1
OR (@c1 IS NULL AND T.c1 IS NULL)
)
AND
(
T.c2 = @c2
OR (@c2 IS NULL AND T.c2 IS NULL)
);
-- Using INTERSECT
SELECT *
FROM @T AS T
WHERE EXISTS
(
SELECT T.c1, T.c2
INTERSECT
SELECT @c1, @c2
);
-- Using separate queries
IF @c1 IS NULL AND @c2 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 IS NULL
AND T.c2 IS NULL
ELSE IF @c1 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 IS NULL
AND T.c2 = @c2
ELSE IF @c2 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 = @c1
AND T.c2 IS NULL
ELSE
SELECT *
FROM @T AS T
WHERE T.c1 = @c1
AND T.c2 = @c2;
-- Using OPTION (RECOMPILE)
-- Requires 2008 SP1 CU5 or later
SELECT *
FROM @T AS T
WHERE
(
T.c1 = @c1
OR (@c1 IS NULL AND T.c1 IS NULL)
)
AND
(
T.c2 = @c2
OR (@c2 IS NULL AND T.c2 IS NULL)
)
OPTION (RECOMPILE);