I trigger vengono compilati ogni volta?


22

Stiamo risolvendo un problema con un server che ha un elevato utilizzo della CPU. Dopo aver scoperto che le query non lo stavano davvero causando, abbiamo iniziato a esaminare le compilation.

Performance Monitor mostra meno di 50 compilazioni / sec e meno di 15 ricompilazioni / sec.

Dopo aver eseguito una sessione XE in cerca di compilation, stiamo vedendo migliaia di compilation al secondo.

Questo sistema utilizza i trigger per controllare le modifiche. La maggior parte delle compilation sono dovute a trigger. Il trigger fa riferimento a sys.dm_tran_active_transactions.

Il nostro primo pensiero era che forse fare riferimento a un DMV in un trigger avrebbe causato la sua compilazione ogni volta, o forse solo questo DMV specifico lo avrebbe causato. Quindi ho iniziato a provare questa teoria. Viene compilato ogni volta, ma non avevo verificato se un trigger viene compilato ogni volta che viene attivato quando non fa riferimento al DMV e codifica invece un valore. Si stava ancora compilando ogni volta che veniva attivato. Rilasciando il trigger si interrompe la compilazione.

  1. Stiamo usando sqlserver.query_pre_execution_showplan in una sessione XE per tenere traccia delle compilazioni. Perché c'è una discrepanza tra questo e il contatore PerfMon?
  2. È normale ricevere un evento di compilazione ogni volta che viene eseguito un trigger?

Script di riproduzione:

CREATE TABLE t1 (transaction_id int, Column2 varchar(100));
CREATE TABLE t2 (Column1 varchar(max), Column2 varchar(100));
GO

CREATE TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT (SELECT TOP 1 transaction_id FROM sys.dm_tran_active_transactions), Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row1', 'value1');
INSERT INTO t2 VALUES ('row2', 'value2');
GO

ALTER TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT 1000, Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row3', 'value3');
INSERT INTO t2 VALUES ('row4', 'value4');

DROP TRIGGER t2_ins;

--These do not show compilation events
INSERT INTO t2 VALUES ('row5', 'value5');
INSERT INTO t2 VALUES ('row6', 'value6');

DROP TABLE t1, t2;

Risposte:


20

L'evento XE in uso ti porta erroneamente a pensare che il trigger stia effettivamente compilando ogni esecuzione. Esistono due eventi estesi query_pre_execution_showplan e query_post_compilation_showplan che hanno descrizioni simili, ma differiscono per una parola importante:

query_pre_execution_showplan

Si verifica dopo la compilazione di un'istruzione SQL. Questo evento restituisce una rappresentazione XML del piano di query stimato che viene generato quando la query viene ottimizzata . L'utilizzo di questo evento può comportare un notevole sovraccarico di prestazioni, pertanto deve essere utilizzato solo per la risoluzione dei problemi o il monitoraggio di problemi specifici per brevi periodi di tempo.

query_post_compilation_showplan

Si verifica dopo la compilazione di un'istruzione SQL. Questo evento restituisce una rappresentazione XML del piano di query stimato che viene generato al momento della compilazione della query . L'utilizzo di questo evento può comportare un notevole sovraccarico di prestazioni, pertanto deve essere utilizzato solo per la risoluzione dei problemi o il monitoraggio di problemi specifici per brevi periodi di tempo.

Gli eventi non sono esattamente gli stessi nella descrizione e si verificano in momenti diversi da ulteriori test con la tua riproduzione. Usando una definizione di sessione di evento molto più ampia, è facile vedere dove stanno realmente avvenendo le compilation.

inserisci qui la descrizione dell'immagine

Qui puoi vedere la prima compilazione in corso per le istruzioni insert mentre i piani preparati vengono parametrizzati automaticamente nella casella verde. Il trigger viene compilato nella casella rossa e il piano viene inserito nella cache come mostrato dall'evento sp_cache_insert. Quindi nella casella arancione l'esecuzione del trigger ottiene un hit nella cache e riutilizza il piano trigger per la seconda istruzione INSERT nel batch, quindi non sta compilando tutte le esecuzioni del comando INSERT e il piano viene riutilizzato come puoi vedere con l'evento sp_cache_hit per il grilletto.

Se eseguiamo le due istruzioni INSERT di nuovo singolarmente dopo la prima esecuzione, il trigger non viene compilato di nuovo come mostrato negli eventi seguenti:

inserisci qui la descrizione dell'immagine

Qui la prima istruzione rileva un hit nella cache per la versione parametrizzata automatica dell'istruzione nella cache, ma manca un batch ad hoc che è stato inviato. Il trigger ottiene un hit nella cache e non viene più compilato come mostrato nel blocco rosso di eventi. Il blocco verde di eventi ripete questo comportamento per la seconda istruzione INSERT eseguita come batch separato. Tuttavia, in ogni caso vedi ancora l'attivazione dell'evento query_pre_execution_showplan che posso solo attribuire alla differenza nell'ottimizzazione rispetto alla compilazione nella descrizione dell'evento, ma il trigger non si sta compilando per ogni esecuzione come mostrato da queste serie di eventi.


Se si osserva il primo screenshot, l'evento sql_batch_statistics non memorizzato si trova nella raccolta ma si attiva solo per la prima esecuzione del batch sql quando la cache viene cancellata e il piano con parametri automatici per gli INSERT non si trova nella cache del piano. Successivamente l'evento uncached_sql_batch_statistics non si attiva più.
Jonathan Kehayias,

Query_post_compilation_showplan ha mostrato solo alcune compilation sui trigger, ma non l'enorme quantità che stavamo vedendo sull'altro evento. Abbiamo trovato alcune pepite interessanti con query_post_compilation_showplan. Grazie per l'informazione, Jonathan!
Tara Kizer,

13

No. I trigger non sono sempre ricompilati. Tuttavia, le istruzioni di query semplici non memorizzano nella cache i loro piani e pertanto vengono sempre ricompilati.

I trigger vengono ricompilati se il numero di righe inserite o eliminate cambia in modo significativo. Vedi: https://technet.microsoft.com/en-us/library/ms181055.aspx

Non so se hanno lo stesso in XEvents, ma in SQL Trace, una ricompilazione ha una sottoclasse di eventi che spiega perché è stata ricompilata. Questo è spiegato nello stesso link sopra.


1
Stavamo guardando le compilation piuttosto che le ricompilazioni. Domani esamineremo il server e verificheremo se è dovuto a una semplice istruzione di query o se è dovuto al numero di righe. Grazie!
Tara Kizer,
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.