Quando sp_executesql aggiorna il piano di query?


13

Dovrai perdonare la mia ingenuità poiché non sono un DBA, ma la mia comprensione è che nel tempo le statistiche di una modifica del database e una procedura memorizzata devono essere ricompilate per mantenere aggiornato il piano di query con le ultime statistiche.

Considerando che io ho una procedura immagazzinata nel mio database che viene ricompilato contro le ultime statistiche in alcuni intervalli regolari, quali sono le implicazioni di in-rivestimento della stored procedure in codice e avvolgendolo in una sp_executesqldichiarazione? Perdo l'aggiornamento del piano di query utilizzato in precedenza durante la ricompilazione della procedura?

Se c'è qualcos'altro (diverso dalle autorizzazioni) che devo considerare prima di apportare questa modifica, apprezzerei le tue intuizioni.

Ho letto questo su MSDN:

La capacità di Query Optimizer di SQL Server di abbinare la nuova stringa Transact-SQL a un piano di esecuzione esistente è ostacolata dai valori dei parametri in costante cambiamento nel testo della stringa, in particolare nelle complesse istruzioni Transact-SQL.

Quindi, supponendo che la procedura memorizzata che sto tentando di sp_executesqlincorporare e racchiudere in effetti contenga alcuni parametri, sta dicendo che sebbene il mio piano di esecuzione sia memorizzato nella cache, sto rendendo più difficile per SQL Server trovarlo e riutilizzarlo?

Risposte:


7

La linea da MSDN sta parlando dell'utilizzo EXEC(), in questo modo:

SET @sql = 'SELECT foo FROM dbo.bar WHERE x = ''' + @x + ''';';
EXEC(@sql);

Nel mio test, le versioni moderne di SQL Server sono ancora in grado di riutilizzare un piano come questo, ma potrebbero esserci altre variabili (come la versione o, ad esempio, se aggiungi WHEREclausole condizionali basate sulla presenza di determinati parametri - nel qual caso genererà un piano diverso).

Se si utilizzano, sp_executesqli valori dei parametri possono comunque causare problemi di sniffing dei parametri (proprio come con il normale SQL), ma ciò non ha nulla a che fare con il fatto che SQL Server possa riutilizzare il piano. Questo piano verrà utilizzato più e più volte, proprio come se non lo avessi usato sp_executesqlaffatto, a meno che non vengano ricompilate variabili che provocherebbero la ricompilazione di una query diretta, nel qual caso verrà ricompilata anche questa (in sostanza, SQL Server no memorizzare qualcosa con il piano che dice "questo è stato eseguito da sp_executesql, ma questo non lo era):

SET @sql = N'SELECT foo FROM dbo.bar WHERE x = @x;';
EXEC sp_executesql @sql, N'@x VARCHAR(32)', @x;

Come bonus, questo ha una protezione integrata contro SQL dinamico ed evita di doverti preoccupare di raddoppiare le virgolette singole a causa dei delimitatori di stringa. Ho blog su questo argomento qui .

Se si hanno problemi con piano di riutilizzo e / o il parametro sniffing, alcune cose che si dovrebbe esaminare sono OPTION (RECOMPILE), OPTIMIZE FOR, optimize for ad hoc workloadse simple/forced parameterization. Ho risposto ad alcune domande simili in risposta a un recente webcast qui, potrebbe valere la pena di scremare:

http://sqlperformance.com/performance-palooza

L'essenza è: non abbiate paura di usarlo sp_executesql, ma usatelo solo quando ne avete bisogno e spendete energia solo per ottimizzarlo eccessivamente quando avete un reale problema di prestazioni. L'esempio sopra è terribile perché non c'è motivo di usare SQL dinamico qui - ho scritto questa risposta supponendo che tu abbia un caso d'uso legittimo.


2

Le query eseguite tramite sp_executesql seguono le stesse regole dei piani di esecuzione delle query normali che non vengono eseguite tramite sp_executesql. Se il testo della query cambia, viene creato un nuovo piano. Se il testo non cambia a causa dell'utente dei parametri, il piano viene riutilizzato. Quando le statistiche vengono aggiornate, i piani scadono e i nuovi piani vengono generati alla successiva esecuzione della query.


Grazie per la tua risposta, ho apportato una modifica ai parametri poiché mi sono reso conto che ogni volta che chiamo sp_ExecuteSql userò una stringa diversa come query a causa del fatto che, dal punto di vista di SQL Server, ho sostituito i parametri con valori hard coded (verranno inseriti in codice prima di inviare la mia query a SQL Server). Conosci un modo per aggirare questo? Dichiarare le variabili nella mia istruzione sql in linea aiuterebbe l'ottimizzatore di query a trovare il mio piano di query memorizzato nella cache?
James Lewis,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.