Introduzione
Query Optimizer di SQL Server utilizza le statistiche durante la compilazione delle query per determinare il piano di query ottimale. Per impostazione predefinita, se l'ottimizzatore rileva che una statistica non è aggiornata a causa di troppe modifiche a una tabella, aggiornerà la statistica immediatamente prima che la compilazione della query possa continuare (solo le statistiche necessarie, non tutte le statistiche per la tabella) .
Si noti che "troppi" non è specifico perché varia in base alla versione e se il flag di traccia 2371 è abilitato:vedere la sezione AUTO_UPDATE_STATISTICS di questa pagina per i dettagli.
Il problema con gli aggiornamenti sincroni delle statistiche
L'aggiornamento sincrono delle statistiche prima della compilazione introduce ovviamente un ritardo e richiede più tempo per la compilazione e l'esecuzione della query. L'entità del ritardo dipende da diversi fattori, tra cui:
- Quante tabelle coinvolte nella query hanno raggiunto la soglia "troppe modifiche"
- Quante statistiche per ciascuna di queste tabelle devono essere aggiornate perché sono necessarie per la compilazione
- Quante righe ci sono nelle tabelle coinvolte
- Le opzioni specificate al momento della creazione di ciascuna statistica (ad es. FULLSCAN e PERSIST_SAMPLE_PERCENT=ON)
Pertanto, può verificarsi un ritardo apparentemente casuale, che potrebbe causare problemi in alcuni scenari, soprattutto se un'applicazione ha un timeout della query molto basso impostato.
Evitare gli aggiornamenti sincroni delle statistiche
Esistono vari modi per evitare gli aggiornamenti sincroni delle statistiche, ad esempio:
- L'impostazione di AUTO_UPDATE_STATISTICS su OFF, disattiva tutti gli aggiornamenti automatici e significa che dovrai eseguire la manutenzione delle tue statistiche per evitare la possibilità di piani di query non ottimali da statistiche non aggiornate.
- Impostando AUTO_UPDATE_STATISTICS_ASYNC su ON, così quando l'ottimizzatore rileva che una statistica deve essere aggiornata, continua con la compilazione e un'attività in background aggiorna la statistica un po' più tardi. Funziona solo se hai anche AUTO_UPDATE_STATISTICS impostato su ON.
- Esegui una regolare manutenzione delle statistiche, in modo che gli aggiornamenti automatici sincroni o asincroni delle statistiche non avvengano affatto.
C'è molto dibattito nella community di SQL Server sull'opportunità di abilitare gli aggiornamenti delle statistiche asincroni. Ho chiesto alla mia adorabile moglie, Kimberly L. Tripp, qual è la sua opinione, e lei consiglia sempre di abilitarla, e si è dimenticata delle statistiche più di quanto potrò mai sapere, quindi le credo. ☺
Tracciamento degli aggiornamenti delle statistiche sincrone
Non c'è mai stato un modo ovvio per sapere se una query stava impiegando molto tempo perché era in attesa di un aggiornamento sincrono delle statistiche. Potresti dire *dopo* che l'aggiornamento delle statistiche è stato completato se avevi già una sessione di evento esteso in esecuzione guardando auto_stats evento e filtraggio su asincrono colonna è impostata su 0. Tuttavia, quella colonna nell'output dell'evento è stata aggiunta solo in SQL Server 2017 e dovresti anche configurare un'azione che acquisisca qualcosa per identificare la query coinvolta.
Ora in SQL Server 2019 è presente il tipo di attesa WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE e, a prima vista, sembra che ti consenta facilmente di vedere se una query è in attesa di un aggiornamento sincrono delle statistiche semplicemente guardando in sys.dm_os_waiting_tasks per vedere quale è attualmente la query aspettando.
Sfortunatamente, non è così.
Il termine "attesa" qui è un po' fuorviante poiché in questo caso il thread non sta effettivamente aspettando. Questo nuovo tipo di attesa è un esempio di quella che viene chiamata attesa "preemptiva", in cui il thread passa a una modalità in cui rimane sul processore fino a quando non ha terminato il suo lavoro. La maggior parte delle attese preventive si verifica quando un thread effettua una chiamata all'esterno di SQL Server (ad esempio, per ottenere informazioni sulla sicurezza da un controller di dominio), ma a volte un thread sta facendo qualcosa all'interno di SQL Server e deve completarlo prima di essere potenzialmente costretto a cedere il processore perché il suo quantum di thread di 4 ms è scaduto. Nessuna di queste cose è ciò che sta accadendo qui. In questo caso, il thread registra l'inizio di un'attesa preventiva con il nuovo tipo di attesa e quindi esegue l'aggiornamento delle statistiche, probabilmente incorrendo in altre *reali* attese come PAGEIOLATCH_SH lungo il percorso. È solo quando l'aggiornamento delle statistiche è completato che l'attesa preventiva termina e viene contabilizzata nelle metriche delle statistiche di attesa.
Perché questo è un grosso problema? Bene, il DMV sys.dm_os_waiting_tasks mostra i tipi di attesa per tutti i thread che sono *realmente* in attesa, cioè nell'elenco delle attività in attesa di uno scheduler, quindi se il thread di aggiornamento delle statistiche sincrone non è in attesa di WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE, quel tipo di attesa non verrà visualizzato nell'output del DMV. Il nuovo tipo di attesa non può essere utilizzato per vedere se una query è attualmente in attesa di un aggiornamento delle statistiche.
Puoi facilmente dimostrarlo a te stesso procedendo come segue:
- Crea una tabella con poche centinaia di migliaia di righe
- Crea una statistica su una colonna della tabella e specifica FULLSCAN e PERSIST_SAMPLE_PERCENT =ON come opzioni, forzando la lettura dell'intera tabella ogni volta che la statistica viene aggiornata
- Aggiorna ventimila righe
- Verifica il database ed esegui DBCC DROPCLEANBUFFERS
- Esegui un'istruzione SELECT con una clausola WHERE sulla colonna con la statistica che hai creato
- Cerca in sys.dm_os_waiting_tasks DMV l'ID sessione di SELECT e vedrai che probabilmente sta aspettando PAGEIOLATCH_SH mentre l'aggiornamento delle statistiche legge la tabella
Con quella delusione a parte, c'è un trucco per essere in grado di vedere se una query è in attesa di un aggiornamento sincrono delle statistiche. Quando si verifica un aggiornamento delle statistiche, viene eseguito un comando chiamato STATMAN e puoi vederlo accadere nell'output di sys.dm_exec_requests :lo stato sarà "sospeso" (anche se il thread è in esecuzione, come ho descritto sopra) e il comando sarà "SELECT (STATMAN)."
A cosa serve il nuovo tipo di attesa?
Sebbene il nuovo tipo di attesa non possa essere utilizzato come un modo immediato per indicare che una query è in attesa di un aggiornamento sincrono delle statistiche, se viene visualizzato nella normale analisi delle statistiche di attesa, sai che alcune query nel carico di lavoro potrebbero soffrire di questi ritardi . Ma questo è il limite della sua utilità per quanto mi riguarda. A meno che il tempo di attesa medio non si presenti come una percentuale preoccupante del tempo medio di esecuzione delle query o non si acquisiscano continuamente le attese in piccoli periodi di tempo per consentire un'analisi corretta, non si sa con certezza se c'è un problema.
Questo è un tipo di attesa in cui il tempo di attesa può variare notevolmente, a seconda dei fattori che ho menzionato in precedenza. Pertanto, userei solo la presenza di questo tipo di attesa per essere avvisato di potenziali problemi e vorrei implementare una sessione di eventi estesi come descritto sopra per acquisire istanze di aggiornamenti statistici sincroni per vedere se la loro durata è abbastanza lunga da meritare prendendo qualche azione correttiva.
Riepilogo
Non sono sicuro che l'aggiunta del tipo di attesa WAIT_ON_SYNCHRONOUS_STATISTICS_UPDATE cambierà se le persone configurano aggiornamenti delle statistiche asincrone o semplicemente eseguono tutte le operazioni di manutenzione delle statistiche da sole, ma almeno ora sarai in grado di dire se le query sono in attesa di statistiche sincrone aggiornamenti e intraprendere ulteriori azioni.
Alla prossima volta, buona risoluzione dei problemi relativi alle prestazioni!