Eu tenho esta instrução SQL:
select *
from _my_table1
where 1 = 0
and (exists (select 1 from _my_table2 where id =7))
O plano de execução é:
|--Constant Scan
Agora, quando mudo minha consulta para
Declare @i int = 1
SELECT *
FROM dbo._my_table1
WHERE @i = 0 AND (EXISTS (SELECT 1 FROM dbo._my_table2 WHERE id = 7))
Eu recebo o seguinte plano:
|--Nested Loops(Left Semi Join)
|--Filter(WHERE:(STARTUP EXPR([@i]=(0))))
| |--Clustered Index Scan(OBJECT:([DEV-RWA_IECMS-DE_Staging_20160301].[dbo].[_my_table1].[PK___my_tabl__3213E83FEF434214]))
|--Clustered Index Seek(OBJECT:([DEV-RWA_IECMS-DE_Staging_20160301].[dbo].[_my_table2].[PK___my_tabl__3213E83F4D4FA6E2]), SEEK:([DEV-RWA_IECMS-DE_Staging_20160301].[dbo].[_my_table2].[id]=(7)) ORDERED FORWARD)
A questão é por que o SQL Server verifica a segunda parte da WHERE
cláusula, se a primeira parte retornar false. Existe alguma solução alternativa para forçar o SQL Engine a não verificar a segunda parte de where, se a primeira parte retornar false.
OPTION (RECOMPILE)
é seu amigo aqui. O SQL Server não tem ideia de qual@i
será o valor no tempo de execução, então ele compila um plano que funcionará para qualquer valor de parâmetro.Forçar a recompilação substituirá esse comportamento e produzirá um plano com uma verificação constante.
Exemplo:
Se você capturar o plano de execução real, ele conterá apenas uma varredura constante. Sem
OPTION (RECOMPILE)
ele contém o plano regular.