(Pergunta movida de SO)
Eu tenho uma tabela (dados fictícios) com índice clusterizado contém 2 colunas:
Agora eu executo essas duas consultas:
declare
@productid int =1 ,
@priceid int = 1
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid OR @productid IS NULL)
AND (priceid = @priceid OR @priceid IS NULL)
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid)
AND (priceid = @priceid)
O plano de execução real para ambas as consultas é:
Como você pode ver, o primeiro está usando o SCAN enquanto o segundo está usando o SEEK.
No entanto - adicionando OPTION (RECOMPILE)
à primeira consulta, fez o plano de execução também usar SEEK:
Amigos no bate-papo do DBA me disseram que:
Na sua consulta, @ productid = 1, o que significa que (productID = @ productID OR @productID IS NULL) pode ser simplificado para (productID = @ productID). O primeiro requer uma varredura para funcionar com qualquer valor de @productID; o último pode usar uma busca. Portanto, quando você usa RECOMPILE, o SQL Server analisa qual valor você realmente possui no @productID e faz o melhor plano para isso. Com um valor não nulo em @productID, é melhor procurar. Se o valor de @productID for desconhecido, o plano deverá se adequar a qualquer valor possível em @productID, o que exigiria uma varredura. Esteja avisado: OPTION (RECOMPILE) forçará uma recompilação do plano toda vez que você o executar, o que adicionará alguns milissegundos a cada execução. Embora isso seja apenas um problema se a consulta for executada com muita frequência.
Além disso :
Se @productID for nulo, qual valor você procuraria? Resposta: não há nada a procurar. Todos os valores são qualificados.
Eu entendo que isso OPTION (RECOMPILE)
força o SQL Server a ver quais valores reais os parâmetros têm e ver se ele pode BUSCAR com ele.
Mas agora eu perco o benefício da compilação à frente.
Questão
IMHO - SCAN só ocorrerá se um parâmetro for nulo.
Tudo bem - deixe o SQL SERVER criar um plano de execução para o SCAN.
MAS, se o SQL Server perceber que eu executo essa consulta muitas vezes com valores:, 1,1
então por que ele não cria OUTRO plano de execução e usa SEEK para isso?
AFAIK - SQL cria plano de execução para as consultas mais atingidas .
Por que o SQL SERVER não salva um plano de execução para:
@productid int =1 , @priceid int = 1
(Eu corro muitas vezes com esses valores)
- É possível forçar o SQL a manter esse plano de execução (que usa o SEEK) - para invocação futura?