(Domanda spostata da SO)
Ho una tabella (dati fittizi) con indice cluster contenente 2 colonne:
Ora eseguo queste due query:
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)
Il piano di esecuzione effettivo per entrambe le query è:
Come puoi vedere, il primo utilizza SCAN mentre il secondo utilizza SEEK.
Tuttavia - aggiungendo OPTION (RECOMPILE)
alla prima query, il piano di esecuzione ha reso anche l'uso di SEEK:
Gli amici della chat DBA mi hanno detto che:
Nella tua query, @ productid = 1, il che significa che (productID = @ productID OR @productID IS NULL) può essere semplificato in (productID = @ productID). Il primo richiede una scansione per funzionare con qualsiasi valore di @productID, il secondo potrebbe utilizzare una ricerca. Pertanto, quando si utilizza RECOMPILE, SQL Server esaminerà il valore effettivamente presente in @productID e farà il piano migliore per esso. Con un valore non nullo in @productID, una ricerca è la migliore. Se il valore di @productID è sconosciuto, il piano deve adattarsi a qualsiasi valore possibile in @productID, che richiederebbe una scansione. Attenzione: OPTION (RECOMPILE) imporrà una ricompilazione del piano ogni volta che lo esegui, il che aggiungerà qualche millisecondo a ogni esecuzione. Anche se questo è un problema solo se la query viene eseguita molto frequentemente.
Anche :
Se @productID è null, a quale valore vorresti cercare? Risposta: non c'è niente da cercare. Tutti i valori si qualificano.
Capisco che OPTION (RECOMPILE)
costringe SQL Server a vedere quali valori effettivi hanno i parametri e vedere se riesce a SEEK con esso.
Ma ora perdo il vantaggio della compilazione anticipata.
Domanda
IMHO - SCAN si verificherà solo se un parametro è nullo.
Va bene: lascia che SQL SERVER crei un piano di esecuzione per SCAN.
MA se SQL Server vede che eseguo questa query molte volte con valori 1,1
:, allora perché non crea UN ALTRO piano di esecuzione e non utilizza SEEK per questo?
AFAIK - SQL crea un piano di esecuzione per le query più colpite .
Perché SQL SERVER non salva un piano di esecuzione per:
@productid int =1 , @priceid int = 1
(Lo eseguo molte volte con quei valori)
- È possibile forzare SQL a mantenere quel piano di esecuzione (che utilizza SEEK) - per invocazioni future?