La domanda è
SELECT SUM(Amount) AS SummaryTotal
FROM PDetail WITH(NOLOCK)
WHERE ClientID = @merchid
AND PostedDate BETWEEN @datebegin AND @dateend
La tabella contiene 103.129.000 righe.
Il piano veloce cerca ClientId con un predicato residuo sulla data, ma deve recuperare 96 ricerche per recuperarlo Amount
. La <ParameterList>
sezione del piano è la seguente.
<ParameterList>
<ColumnReference Column="@dateend"
ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
<ColumnReference Column="@datebegin"
ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
<ColumnReference Column="@merchid"
ParameterRuntimeValue="(78155)" />
</ParameterList>
Il piano lento cerca per data e dispone di ricerche per valutare il predicato residuo su ClientId e recuperare l'importo (stimato 1 rispetto a 7.388.383 effettivi). La <ParameterList>
sezione è
<ParameterList>
<ColumnReference Column="@EndDate"
ParameterCompiledValue="'2013-02-01 23:59:00.000'"
ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
<ColumnReference Column="@BeginDate"
ParameterCompiledValue="'2013-01-01 00:00:00.000'"
ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
<ColumnReference Column="@ClientID"
ParameterCompiledValue="(78155)"
ParameterRuntimeValue="(78155)" />
</ParameterList>
In questo secondo caso il nonParameterCompiledValue
è vuoto. SQL Server ha sniffato correttamente i valori utilizzati nella query.
Il libro "Risoluzione dei problemi pratici di SQL Server 2005" dice questo sull'uso delle variabili locali
L'uso di variabili locali per sconfiggere lo sniffing dei parametri è un trucco abbastanza comune, ma i suggerimenti OPTION (RECOMPILE)
e OPTION (OPTIMIZE FOR)
... sono generalmente soluzioni più eleganti e leggermente meno rischiose
Nota
In SQL Server 2005, la compilazione a livello di istruzione consente di rinviare la compilazione di una singola istruzione in una procedura memorizzata fino a poco prima della prima esecuzione della query. A quel punto il valore della variabile locale sarebbe noto. Teoricamente SQL Server potrebbe trarne vantaggio per annusare i valori delle variabili locali nello stesso modo in cui annusa i parametri. Tuttavia, poiché era comune utilizzare le variabili locali per annullare lo sniffing dei parametri in SQL Server 7.0 e SQL Server 2000+, lo sniffing delle variabili locali non era abilitato in SQL Server 2005. Potrebbe essere abilitato in una futura versione di SQL Server, sebbene sia un buon motivo per utilizzare una delle altre opzioni descritte in questo capitolo se hai una scelta.
Da un test rapido questo fine il comportamento descritto sopra è sempre lo stesso nel 2008 e nel 2012 e le variabili non vengono sniffate per la compilazione differita ma solo quando OPTION RECOMPILE
viene utilizzato un suggerimento esplicito .
DECLARE @N INT = 0
CREATE TABLE #T ( I INT );
/*Reference to #T means this statement is subject to deferred compile*/
SELECT *
FROM master..spt_values
WHERE number = @N
AND EXISTS(SELECT COUNT(*) FROM #T)
SELECT *
FROM master..spt_values
WHERE number = @N
OPTION (RECOMPILE)
DROP TABLE #T
Nonostante la compilazione differita, la variabile non viene sniffata e il conteggio delle righe stimato non è preciso
Quindi presumo che il piano lento si riferisca a una versione con parametri della query.
Il ParameterCompiledValue
è uguale ParameterRuntimeValue
per tutti i parametri quindi questo non è tipico parametro sniffing (dove il piano è stato compilato per un insieme di valori quindi eseguire un altro insieme di valori).
Il problema è che il piano che viene compilato per i valori dei parametri corretti è inappropriato.
Probabilmente stai colpendo il problema con le date ascendenti descritte qui e qui . Per una tabella con 100 milioni di righe è necessario inserire (o modificare in altro modo) 20 milioni prima che SQL Server aggiorni automaticamente le statistiche. Sembra che l'ultima volta che sono state aggiornate zero righe corrispondessero all'intervallo di date nella query, ma ora 7 milioni lo fanno.
È possibile pianificare aggiornamenti delle statistiche più frequenti, prendere in considerazione i flag di traccia 2389 - 90
o utilizzarli in OPTIMIZE FOR UKNOWN
modo da ricadere su ipotesi piuttosto che essere in grado di utilizzare le statistiche attualmente fuorvianti nella datetime
colonna.
Ciò potrebbe non essere necessario nella prossima versione di SQL Server (dopo il 2012). Un elemento Connect correlato contiene la risposta intrigante
Inserito da Microsoft il 28/08/2012 alle 13:35
Abbiamo apportato un miglioramento alla stima della cardinalità per la prossima versione principale che risolve sostanzialmente questo problema. Resta sintonizzato per i dettagli una volta pubblicate le anteprime. Eric
Questo miglioramento del 2014 viene esaminato da Benjamin Nevarez verso la fine dell'articolo:
Un primo sguardo al nuovo stimatore della cardinalità di SQL Server .
Sembra che il nuovo stimatore della cardinalità ricadrà e utilizzerà la densità media in questo caso anziché fornire la stima a 1 riga.
Alcuni dettagli aggiuntivi sullo stimatore della cardinalità 2014 e il problema chiave crescente qui:
Nuove funzionalità in SQL Server 2014 - Parte 2 - Nuova stima della cardinalità