Sì, lo farà.
Esistono due differenze principali tra OPTION(OPTIMIZE FOR UNKNOWN)
e OPTION(RECOMPILE)
come si può vedere da questa citazione da MSDN
:
Quindi, le due differenze principali sono:
- Memorizzazione nella cache (o meno) del piano di query.
Di solito il piano di query generato viene memorizzato nella cache e riutilizzato. OPTIMIZE FOR UNKNOWN
non pregiudica questa caratteristica del motore. RECOMPILE
sopprime questa funzione e dice al motore di eliminare il piano e di non inserirlo nella cache.
- Utilizzo (o meno) dei valori dei parametri effettivi durante la generazione del piano.
Solitamente l'ottimizzatore "annusa" i valori dei parametri e utilizza questi valori durante la generazione del piano. OPTIMIZE FOR UNKNOWN
sopprime questa funzione e dice al motore di trattare tutti i parametri come se i loro valori fossero sconosciuti. L'ottimizzatore ha regole ed euristiche integrate su come utilizzare le statistiche disponibili per vari criteri di filtro. Vedi Ottimizza per... Mediocre?
per ulteriori dettagli. Normalmente lo sniffing dei parametri viene utilizzato alla prima esecuzione della query/stored procedure e utilizza i valori dei parametri durante la prima esecuzione. Il piano generato viene memorizzato nella cache e in seguito può essere riutilizzato.
Una cosa non ovvia da ricordare qui è che in entrambi i casi (normale senza alcun suggerimento di query e con OPTIMIZE FOR UNKNOWN
suggerimento) il piano generato deve essere valido e produrre un risultato corretto per qualsiasi possibile valore del parametro. È adattato ai valori sniffati che sono stati utilizzati durante la prima esecuzione nel caso normale/senza suggerimenti; non è adattato a nessun valore specifico in OPTIMIZE FOR UNKNOWN
caso, ma è ancora valido se il parametro cambia in un secondo momento in qualsiasi modo.
Questo è significativo e impedisce all'ottimizzatore di eseguire determinate trasformazioni e semplificazioni del piano.
OPTION(RECOMPILE)
consente all'ottimizzatore di incorporare i valori effettivi dei parametri durante ogni corsa e l'ottimizzatore utilizza i valori effettivi dei parametri per generare un piano migliore. Non devi preoccuparti che il piano generato potrebbe non funzionare con qualche altro valore di parametro, perché il piano non verrà memorizzato nella cache e riutilizzato.
Questo effetto è visibile principalmente per le Condizioni di ricerca dinamica interrogazioni. Ad esempio:
SELECT ...
FROM T
WHERE
(@ParamSomeID = 0)
OR
(
@ParamSomeID = -1
AND
T.SomeID NOT IN
(
SELECT OtherTable.SomeID
FROM OtherTable
)
)
OR
(
T.SomeID IN
(
SELECT OtherTable.SomeID
FROM OtherTable
WHERE OtherTable.SomeID = @ParamSomeID
)
)
OPTION(RECOMPILE)
Se @ParamSomeID
è 0
l'ottimizzatore tratterebbe la query come se non avesse alcun WHERE
clausola affatto. Il piano non menzionerebbe OtherTable
affatto.
Se @ParamSomeID
è -1
, il piano si unirebbe a T
a OtherTable
utilizzando Left Anti Semi Join e scansiona l'intera OtherTable
.
Se @ParamSomeID
è, diciamo, 5, il piano farebbe una ricerca dell'indice nell'indice univoco su OtherTable
e leggi solo una riga da OtherTable
.
Senza OPTION(RECOMPILE)
questo tipo di semplificazione e trasformazione non accadrebbe.
Un altro motivo per usare OPTION(RECOMPILE)
è quando la distribuzione dei dati è molto distorta. Ad esempio, hai una tabella con 1 milione di righe. Una colonna ha valore 0 in 990.000 righe e valori da 1 a 10 in 1.000 righe. Le query che filtrano su questa colonna dovrebbero avere piani diversi a seconda del valore effettivo del filtro.
In entrambi gli esempi sopra OPTIMIZE FOR UNKNOWN
genererebbe un piano mediocre.