Questo fa parte di una serie di cache dei piani interni di SQL Server. Assicurati di leggere il primo post di Kalen su questo argomento.
SQL Server esiste da oltre 30 anni e lavoro con SQL Server da quasi lo stesso tempo. Ho visto molti cambiamenti nel corso degli anni (e decenni!) e delle versioni di questo incredibile prodotto. In questi post condividerò con te come considero alcune delle funzionalità o aspetti di SQL Server, a volte insieme a un po' di prospettiva storica
Nel mio articolo precedente , ho parlato della diagnostica del server SQL, incluse le varie opzioni che SQL Server ha per riutilizzare un piano di query. Abbiamo esaminato tre tipi di piani di query:ad hoc, preparato e procedurale. Ho concluso la discussione con uno sguardo a un riutilizzo inappropriato di un piano, che può verificarsi quando SQL Server applica lo sniffing dei parametri nelle situazioni sbagliate. Se un piano si basa su un valore iniziale che fa sì che l'ottimizzatore generi un piano appropriato per quel valore e quindi lo stesso piano viene utilizzato per un valore diverso, il piano potrebbe non essere più ottimale.
Quindi, cosa possiamo fare quando lo sniffing dei parametri è un problema? Possiamo costringere SQL Server a elaborare un nuovo piano. Di solito, chiamiamo "ricompilare" l'atto di elaborare un nuovo piano, ma probabilmente dovrebbe essere chiamato "riottimizzazione". Tuttavia, la maggior parte delle persone usa il termine "ricompilare", quindi è quello che userò qui.
Se l'uso inappropriato dello sniffing dei parametri è un problema, una soluzione semplice consiste semplicemente nel dire a SQL Server di elaborare un nuovo piano. Per le singole istruzioni, ad esempio con i piani PREPARED che sono stati parametrizzati automaticamente, è possibile aggiungere l'hint RECOMPILE a una query. Utilizzando FORCED parametrizzato (discusso nell'articolo precedente), questa query verrà parametrizzata.
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num;
Se vogliamo essere sicuri di ottenere un nuovo piano ogni volta che eseguiamo questa query, con valori potenzialmente molto diversi per @num, possiamo aggiungere il suggerimento RECOMPILE come mostrato:
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num
OPTION (RECOMPILE);
Per le stored procedure, abbiamo tre opzioni. Innanzitutto, possiamo accertare se la ricompilazione aiuterà effettivamente le prestazioni eseguendo la procedura con l'opzione RICOMPILA:
EXEC get_sales_range 66666 WITH RECOMPILE;
Questa opzione causerà la generazione di un nuovo piano solo per questa esecuzione. Non verrà salvato e di certo non verrà riutilizzato. Il valore usecount mostrato in sp_cacheobjects (descritto nel post precedente) per la procedura non aumenterà poiché il piano originale non viene riutilizzato.
In secondo luogo, se scopriamo che l'esecuzione CON RECOMPILE aiuta, potremmo considerare di ricreare la procedura con l'opzione RECOMPILE, nel qual caso non riutilizzerà mai il piano e la procedura non verrà affatto visualizzata nella cache del piano.
DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
@num int
WITH RECOMPILE
AS
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num;
GO
Per la mia piccola procedura semplice, potrebbe avere senso utilizzare l'opzione WITH RECOMPILE per l'intera procedura. Ma se la procedura è più complessa, potrebbe non avere senso ricompilare l'intera procedura perché un'istruzione sta causando problemi. Quindi, la terza opzione consiste nell'usare l'hint RECOMPILE per un'istruzione all'interno della procedura, quindi appare così:
DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
@num int
AS
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num
OPTION (RECOMPILE);
GO
L'utilizzo di una di queste opzioni RECOMPILE può costringere SQL Server a elaborare un nuovo piano su richiesta. Ora esamineremo quando la diagnostica di SQL Server presenta un nuovo piano quando non lo richiedi, ovvero quando si verifica la ricompilazione automatica di un piano esistente?
La ricompilazione automatica di un piano avviene in due tipi di situazioni:
- In primo luogo, se l'ottimizzatore determina che il piano esistente non è più corretto, in genere a causa di una modifica nelle definizioni degli oggetti, dovrà elaborare un nuovo piano. Ad esempio, se si dispone di un piano per una query che seleziona da TableA e quindi si eliminano diverse colonne o si modificano i tipi di dati delle colonne in TableA, SQL Server ricompila la query per creare un piano che rifletta le modifiche DDL.
- La seconda situazione in cui si verifica la ricompilazione automatica è quando SQL Server determina che il piano potrebbe non essere più ottimale, a causa di una modifica delle statistiche. Nella maggior parte dei casi, se le statistiche su una qualsiasi delle colonne o degli indici sono state aggiornate dall'ultima compilazione del piano, verranno ricompilate. Ma questo porta a un'altra domanda. Quando vengono aggiornate le statistiche? Le statistiche possono essere aggiornate automaticamente quando sono cambiate abbastanza righe nelle colonne pertinenti. quanti ne bastano? Ne parliamo a breve.
Per impostazione predefinita, SQL Server aggiorna automaticamente le statistiche a causa di un'opzione del database attiva per impostazione predefinita. Ma se sei un proprietario di database (o un 'sa' SQL, che appare come proprietario in ogni database), puoi modificare le opzioni. Una delle opzioni si chiama AUTO_UPDATE_STATISTICS e un'altra si chiama AUTO_UPDATE_STATISTICS_ASYNC. L'opzione AUTO_UPDATE_STATISTICS è attiva nel database tempdb, quindi ogni nuovo database eredita questa opzione. Quando questa opzione è attiva e il motore di esecuzione della query rileva le modifiche a un numero sufficiente di righe durante l'elaborazione di una query, l'esecuzione si interromperà mentre le statistiche vengono aggiornate e quindi la query viene ricompilata. L'altra opzione, AUTO_UPDATE_STATISTICS_ASYNC, può potenzialmente avere un effetto minore sul tempo di esecuzione della query perché l'esecuzione non si interrompe, a costo di utilizzare un possibile piano non ottimale. Con la seconda opzione, se il motore di esecuzione rileva la necessità di aggiornare le statistiche, viene attivato un thread in background per eseguire l'aggiornamento e il thread principale continua a eseguire la query con le statistiche originali e il piano originale. La query successiva che accede alle tabelle interessate e vede le statistiche aggiornate ricompila la query, ma non si interrompe ed esegue l'aggiornamento delle statistiche nel mezzo dell'esecuzione.
Ci sono alcune altre situazioni e alcuni suggerimenti per le query che controllano se i piani vengono ricompilati o meno, quindi ti mostrerò un diagramma di flusso Condividerò un diagramma di flusso con te che ho creato per i miei corsi di formazione sui componenti interni di SQL Server.
La freccia è il punto in cui SQL Server avvia l'elaborazione del batch. Per prima cosa controlla se c'è già un piano per il tuo batch nella cache e, se la risposta è NO, segue la freccia a destra e compila un piano. Il piano viene messo nella cache e quindi SQL Server viene riavviato. Sì, questa volta il piano dovrebbe essere nella cache, quindi segue la freccia verso il basso e chiede se è stato utilizzato un suggerimento chiamato KEEP PLAN. Se SÌ, SQL Server avvia immediatamente l'esecuzione del piano e non esegue ulteriori controlli.
La domanda successiva è se sono state apportate modifiche al DDL. Se no, chiede di molte altre situazioni di cui non potrò parlare in questo articolo. In effetti, non ho davvero intenzione di passare attraverso tutte le opzioni qui. Lo lascio a te. Ma se hai domande o confusione, sentiti libero di chiederle nella sezione commenti qui o twittami su @sqlqueen. Indicherò la domanda all'estrema destra:AUTO_STATS_ASYNC ON? Qui puoi vedere che se la risposta è SÌ, ci sono due azioni. Un ramo inizia semplicemente l'esecuzione con il piano esistente e l'altro è il thread in background che aggiorna le statistiche ma poi non fa nient'altro. La query successiva incontrerà la casella di decisione al centro "Sono disponibili nuove statistiche" e dovrebbe rispondere SÌ, quindi la query verrà ricompilata.
L'unica altra cosa di cui parlerò è la domanda "Ci sono statistiche non aggiornate?" Ciò significa sostanzialmente che le statistiche non sono aggiornate perché sono state apportate troppe modifiche. Quindi ora possiamo parlare di quanti sono troppi.
Sebbene vengano utilizzati valori diversi per tabelle molto piccole, per qualsiasi tabella con più di 500 righe, prima di SQL Server 2016 le statistiche venivano considerate "non aggiornate" quando il numero di modifiche alla colonna su cui erano basate le statistiche superava 20 % del numero di righe nella tabella. Quindi, per una tabella di 1000 righe, ciò potrebbe significare 200 inserimenti, 200 aggiornamenti o 200 eliminazioni. Potrebbero essere 200 modifiche di righe o 5 righe aggiornate 40 volte ciascuna. SQL Server ci offre anche una funzione che segnala quante modifiche sono state apportate. Dovrai cercare il numero stats_id per le statistiche che ti interessano, che sarebbe index_id se le statistiche appartengono a un indice. Lo stats_id può essere trovato nella vista chiamata sys.stats. Nella mia tabella newssales, utilizzo questa query per scoprire che stats_id per l'indice nella colonna SubTotal è 3.
SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');
Quindi posso usare quel valore per guardare il numero di modifiche. Fammi aggiornare prima alcune righe:
UPDATE newsales
(1541 righe interessate)
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);
In effetti, il 20% è un numero GRANDE. E per molte tabelle, le query potrebbero trarre vantaggio da statistiche aggiornate con molto meno del 20% delle righe aggiornate. A partire da 2008R2 SP1, SQL Server include un Traceflag che puoi utilizzare per modificare il numero di righe in modo che sia una scala mobile, come mostrato nel grafico seguente:
A partire da SQL Server 2016, questo nuovo algoritmo con scala mobile viene utilizzato per impostazione predefinita, a condizione che tu sia nel livello di compatibilità 130 o superiore.
La maggior parte delle ricompilazioni automatiche dei piani di query è dovuta a modifiche delle statistiche. Ma come ho detto sopra, questo non è l'unico motivo per una ricompilazione. Ma poiché è il più comune, può essere molto utile essere a conoscenza di quando e come vengono aggiornate le statistiche e assicurarsi che le statistiche sulle tabelle critiche vengano aggiornate abbastanza spesso per essere sicuri di ottenere i piani migliori!
Analizza automaticamente i dati sulle prestazioni per eseguire la diagnostica del server SQL per risolvere rapidamente i problemi e identificare i server in cui ha origine il degrado delle prestazioni. Inizia a utilizzare Spotlight Cloud oggi: