Una delle sfide più difficili in SQL Server è la risoluzione dei problemi relativi alla sensibilità dei parametri o alla stima della cardinalità che causano un degrado delle prestazioni di un carico di lavoro. In genere è necessario disporre del piano di esecuzione effettivo dall'istruzione in esecuzione per poter determinare la causa del degrado delle prestazioni. In SQL Server 2012, l'evento esteso query_post_execution_showplan offre la possibilità di acquisire il piano di esecuzione effettivo per le istruzioni. Tuttavia, per quanto utile possa sembrare, questo evento non è qualcosa che può essere utilizzato senza un impatto significativo sulle prestazioni del carico di lavoro in esecuzione sul server.
Nel mio articolo sulla misurazione del "overhead dell'osservatore" di SQL Trace rispetto agli eventi estesi, ho mostrato un confronto dell'impatto sulle prestazioni di SQL Trace rispetto a una configurazione identica che utilizza gli eventi estesi in SQL Server 2012. All'epoca ho eseguito inizialmente il test per quell'articolo Ho anche eseguito numerosi test dell'evento query_post_execution_showplan in SQL Server 2012. Questo evento è stato introdotto per la prima volta in SQL Server 2012 CTP1 quando molti degli eventi di traccia sono stati trasferiti in eventi estesi per fornire la parità con SQL Trace. A quel tempo l'evento aveva solo un sottoinsieme delle colonne incluse nell'RTM finale di SQL Server 2012.
Durante CTP1 ho inviato un elemento Connect richiedendo la creazione di un'azione per consentire la raccolta del piano di esecuzione effettivo con eventi in SQL Server 2012. L'obiettivo era poter utilizzare gli eventi module_end o sql_statement_completed per identificare quando l'esecuzione di una procedura o la dichiarazione supera la sua durata normale. Ad esempio, nello scenario della sensibilità dei parametri, in cui viene generato un piano meno ideale per i valori dei parametri normali, l'evento può essere utilizzato per raccogliere il piano di esecuzione effettivo per tale istruzione tramite un'azione. In risposta, il team di SQL Server ha aggiunto le colonne duration e cpu_time all'evento query_post_execution_showplan per consentire alle definizioni dei predicati di raccogliere questo evento solo per quegli scenari.
Sfortunatamente questo non ha gli stessi vantaggi che un'implementazione come azione avrebbe avuto sulle prestazioni. Nel resto di questo post spiegherò perché.
Impatto sulle prestazioni
Nel momento in cui ho eseguito il test per il mio articolo precedente, ho anche testato l'overhead associato all'evento query_post_execution_showplan, principalmente perché ero davvero interessato a usarlo in un paio di sistemi di produzione client e prima di farlo avevo bisogno di capire cosa tipo di impatto che l'evento avrebbe sul loro carico di lavoro. Sono rimasto davvero costernato dai risultati che ho ottenuto dai miei test originali e, dopo aver fatto convalidare i miei risultati da Aaron Bertrand utilizzando l'imbracatura di prova interna di SQL Sentry, ho archiviato un altro articolo Connect che riportava i problemi di prestazioni che è stato successivamente chiuso come "Per progettazione" .
Per testare l'impatto sulle prestazioni, è stato utilizzato lo stesso carico di lavoro e la stessa configurazione di riproduzione distribuita dall'articolo "Misurazione del sovraccarico dell'osservatore" di SQL Trace rispetto agli eventi estesi. L'unica differenza per i risultati dei test mostrati in questo articolo è che per l'ambiente VM è stato utilizzato un sistema host più nuovo e più potente. Le VM utilizzate erano esattamente le stesse, senza modifiche alla loro configurazione, e sono state semplicemente copiate nel nuovo sistema, motivo per cui il carico di lavoro di base è stato in grado di eseguire la riproduzione più velocemente con una media di richieste batch/sec più elevata. I risultati di base sono stati acquisiti utilizzando un'installazione standard di SQL Server 2012 con solo la sessione dell'evento system_health predefinita in esecuzione sul server.
Per il confronto dell'impatto sulle prestazioni di query_post_execution_showplan
evento, è stata utilizzata la seguente definizione di sessione evento.
CREATE EVENT SESSION [query_post_execution_showplan Overhead] ON SERVER ADD EVENT sqlserver.query_post_execution_showplan( WHERE ([duration]=(5000000))); GO
Questa sessione in realtà non raccoglie i dati dell'evento utilizzando una destinazione e utilizza un predicato sulla durata per la durata dell'evento pari a 5000000 microsecondi o una durata di cinque secondi. Per il carico di lavoro di riproduzione, nessuna istruzione in esecuzione ha una durata esattamente di cinque secondi, quindi l'evento query_post_execution_showplan non viene mai effettivamente attivato nel server e qualsiasi degrado delle prestazioni è strettamente il risultato della raccolta dei dati dell'evento e quindi della valutazione del predicato. I risultati dei test sono mostrati nella Tabella 1 e riportati nella Tabella 2.
Tabella 1 – sovraccarico dell'evento query_post_execution
Grafico 2 – sovraccarico dell'evento query_post_execution
Per questo ciclo di test, le prestazioni del carico di lavoro si riducono di circa il 30% semplicemente attivando questo evento in una sessione dell'evento, anche se non si attiverà per nessuno degli eventi che vengono riprodotti sul server. Il degrado complessivo dipenderà dal carico di lavoro effettivo per il server ed è importante notare che questa serie di test riflette più uno scenario peggiore poiché la riproduzione distribuita è stata eseguita in modalità di stress e l'utilizzo della CPU in SQL Server è stato ancorato al 94% in media durante i test.
Comprendere l'impatto sulle prestazioni
Il motivo per cui questo evento impone un sovraccarico così significativo sulle prestazioni può essere spiegato dal ciclo di vita dell'evento in Eventi estesi. Quando viene rilevato un punto critico nel codice di SQL Server associato a un evento durante l'esecuzione, il codice esegue un controllo booleano molto veloce per determinare se l'evento è abilitato in qualsiasi sessione di eventi attiva sul server. Se l'evento è abilitato per una sessione evento attiva, vengono raccolte tutte le colonne di dati associate all'evento, comprese le colonne personalizzabili che sono state attivate. A questo punto l'evento valuta tutti i predicati per le sessioni di eventi attive che stanno raccogliendo l'evento per determinare se l'evento verrà effettivamente attivato completamente.
Per l'evento query_post_exection_showplan, tutto l'impatto sulle prestazioni deriva dall'overhead associato alla raccolta dei dati. Anche nel caso in cui vi sia un predicato di durata pari a cinque secondi, semplicemente attivando l'evento in una sessione dell'evento, deve raccogliere lo Showplan XML per ogni istruzione che viene eseguita sul server solo per poter valutare il predicato e quindi determinare che l'evento non si attiverà. Per questo motivo, l'evento query_post_execution_showplan dovrebbe essere evitato per i carichi di lavoro di produzione. Per il carico di lavoro di riproduzione del test, l'evento doveva essere valutato circa 440.000 volte, anche se in realtà non si attivava per il carico di lavoro e la sessione dell'evento in fase di test poiché nessuno degli eventi di riproduzione ha una durata di esattamente cinque secondi. Le informazioni sul conteggio degli eventi sono state raccolte aggiungendo la destinazione event_counter alla sessione dell'evento e rimuovendo il predicato della durata, quindi testando nuovamente il carico di lavoro di riproduzione con la seguente definizione di sessione.
CREATE EVENT SESSION [query_post_execution_showplan Overhead] ON SERVER ADD EVENT sqlserver.query_post_execution_showplan ADD TARGET package0.event_counter; GO
Confronto con eventi a attivazione rapida
Per fornire un quadro di riferimento per questo impatto sulle prestazioni, possiamo esaminare il sovraccarico derivante dall'attivazione di una serie di eventi eseguiti di frequente nel server e dall'esecuzione dello stesso carico di lavoro di riproduzione. Due degli eventi eseguiti più frequentemente in SQL Server sono gli eventi lock_acquired e lock_released. Per confrontare l'overhead di questi due eventi, è possibile utilizzare la seguente sessione di eventi, che raccoglie gli eventi senza predicato in modo che ogni esecuzione venga raccolta e conta la frequenza con cui vengono attivati utilizzando la destinazione event_counter.
CREATE EVENT SESSION [locking Overhead] ON SERVER ADD EVENT sqlserver.lock_acquired, ADD EVENT sqlserver.lock_released ADD TARGET package0.event_counter; GO
Per il nostro carico di lavoro di riproduzione, questi due eventi si attivano circa 111.180.000 volte. Il sovraccarico associato alla raccolta di questi eventi può essere visualizzato nella Tabella 3 e nel Grafico 4.
Tabella 3 – Confronto dei costi generali di blocco
Grafico 4 – Confronto dell'overhead degli eventi di blocco
Come puoi vedere dai dati, l'effetto sulle prestazioni di questi eventi è significativamente inferiore rispetto a query_post_execution_showplan, anche se la definizione della sessione dell'evento di blocco è stata configurata per consentire a tutti gli eventi di attivarsi sul server, l'overhead totale è stato complessivamente inferiore all'1% . Tieni presente che la sessione dell'evento di blocco ha valutato l'equivalente di 500 volte più eventi, e in questo caso tutti gli eventi dovevano effettivamente essere attivati per la sessione dell'evento, in cui l'evento query_post_execution_showplan non doveva effettivamente attivarsi dopo essere stato valutato.
Riepilogo
Sebbene l'evento query_post_execution_showplan offra la possibilità di raccogliere il piano di query effettivo per un'istruzione che viene eseguita, l'impatto sulle prestazioni della raccolta di dati solo per valutare l'evento lo rende qualcosa che non è praticabile per l'utilizzo in produzione. Come minimo, è necessario considerare l'overhead prima di utilizzare questo evento contro un carico di lavoro di produzione. Anche la descrizione dell'evento fornita da Microsoft riconosce che l'evento può avere un impatto significativo sulle prestazioni (evidenziazione mia):
Si verifica dopo l'esecuzione di un'istruzione SQL. Questo evento restituisce una rappresentazione XML del piano di query effettivo. L'utilizzo di questo evento può comportare un sovraccarico di prestazioni significativo, quindi dovrebbe essere utilizzato solo durante la risoluzione dei problemi o il monitoraggio di problemi specifici per brevi periodi di tempo.La descrizione dell'evento può essere trovata nella colonna della descrizione della vista del catalogo sys.dm_xe_objects o nell'interfaccia utente della nuova sessione come mostrato nella Figura 5 (la mia evidenziazione):
Figura 5 – Descrizione dell'evento dall'interfaccia utente della nuova sessione
Consiglierei di confrontare le prestazioni di qualsiasi evento con questo avviso nella descrizione prima di utilizzarlo effettivamente in un ambiente di produzione.