Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Trigger di SQL Server:comprensione e alternative

Il trigger di SQL Server è un tipo speciale di stored procedure che viene eseguito automaticamente quando si verifica un evento in un server di database specifico. SQL Server ci fornisce due tipi principali di trigger:il DML Trigger e il DDL trigger. I trigger DDL verranno attivati ​​in risposta a diversi eventi DDL (Data Definition Language), come l'esecuzione di istruzioni CREATE, ALTER, DROP, GRANT, DENY e REVOKE T-SQL. Il trigger DDL può rispondere alle azioni DDL impedendo che queste modifiche influiscano sul database, eseguire un'altra azione in risposta a queste azioni DDL o registrare queste modifiche che vengono eseguite sul database.

Il trigger DML di SQL Server è un tipo speciale di stored procedure progettato per eseguire una sequenza di azioni su una tabella di database, a cui è collegato il trigger, quando si verificano eventi DML (Data Manipulation Language), come INSERT, UPDATE o DELETE azione, si verifica per modificare il contenuto delle tabelle o viste del database, indipendentemente dal fatto che le righe della tabella siano interessate o meno. I trigger differiscono dalle stored procedure in quanto vengono attivati ​​automaticamente quando si verifica una modifica dei dati predefinita. I trigger DML possono essere utilizzati per mantenere l'integrità dei dati e far rispettare le regole aziendali dell'azienda, così come la funzionalità di controllo delle tabelle e vincoli di chiavi esterne, eseguendo processi di controllo e altre azioni successive al DML. Puoi utilizzare i trigger DML per eseguire query su altre tabelle ed eseguire query T-SQL complesse.

Se il trigger viene attivato, un tipo speciale di tabelle virtuali chiamato Inserted e Eliminato le tabelle verranno utilizzate per mantenere i valori dei dati prima e dopo la modifica. L'istruzione trigger funzionerà nell'ambito della stessa transazione che attiva quel trigger. Ciò significa che la transazione non verrà confermata completamente fino a quando l'istruzione trigger non sarà completata correttamente. D'altra parte, la transazione verrà annullata se l'istruzione trigger non riesce.

Esistono due tipi di attivatori DML:AFTER o PER trigger e INVECE DI grilletto. Il trigger AFTER verrà attivato ed eseguito dopo aver eseguito l'azione INSERT, UPDATE o DELETE che lo attiva correttamente. Inoltre, tutte le azioni referenziali a cascata e i controlli dei vincoli dovrebbero avere esito positivo prima di attivare il trigger. Il trigger AFTER può essere definito solo a livello di tabella senza la possibilità di definirlo sulle viste. Il trigger INSTEAD OF viene utilizzato per sovrascrivere l'istruzione dell'azione che attiva il trigger con l'istruzione fornita nel trigger, ripristinando tale istruzione dopo aver generato un errore quando qualcuno sta tentando di eseguire un'azione che viola una politica specifica, come l'aggiornamento una colonna finanziaria critica o scrivere la modifica in una tabella di controllo prima di eseguire la modifica. Il trigger INSTEAD OF consente di INSERIRE, AGGIORNARE o CANCELLARE i dati dalle viste che fanno riferimento ai dati di più tabelle, oltre alla possibilità di rifiutare una parte di una query batch ed eseguire correttamente un'altra parte di quel batch. Il trigger INSTEAD OF non può essere utilizzato con le viste aggiornabili che hanno WITH CHECK OPTION e nelle tabelle con una relazione referenziale che specifica le azioni a cascata su DELETE o UPDATE.

Dopo aver discusso i trigger in teoria, inizieremo a mostrare ciò di cui discutiamo praticamente. Nelle prossime demo, mostreremo le diverse situazioni in cui possiamo trarre vantaggio dai trigger di SQL Server.

DOPO... Attivazione DML

Si supponga di dover tenere traccia delle azioni DML eseguite su una tabella specifica e scrivere questi registri in una tabella della cronologia, in cui l'ID del record inserito, aggiornato o eliminato e l'azione eseguita verranno scritti nella tabella della cronologia. Le istruzioni CREATE TABLE T-SQL riportate di seguito possono essere utilizzate per creare sia le tabelle di origine che quelle cronologiche:

CREATE TABLE TriggerDemo_Parent
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO

CREATE TABLE TriggerDemo_History
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ParentID INT,
   PerformedAction VARCHAR (50),
  )
GO

Per tenere traccia dell'operazione INSERT, creeremo un trigger DML che verrà attivato dopo aver eseguito un'operazione INSERT sulla tabella padre. Questo trigger recupererà l'ultimo valore ID inserito in quella tabella padre dalla tabella inserita virtuale, come nell'istruzione CREATE TRIGGER T-SQL di seguito:

CREATE TRIGGER AfterInsertTrigger
ON TriggerDemo_Parent
AFTER INSERT
AS
INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Insert')
GO

È possibile tenere traccia dell'operazione DELETE creando un trigger DML che viene attivato dopo aver eseguito l'operazione DELETE sulla tabella padre. Anche in questo caso, il trigger recupererà il valore ID dell'ultimo record eliminato da quella tabella padre dalla tabella virtuale eliminata, come nell'istruzione CREATE TRIGGER T-SQL di seguito:

CREATE TRIGGER AfterDeleteTrigger
ON TriggerDemo_Parent
AFTER DELETE
AS
INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1  deleted.ID FROM deleted), 'Delete')
GO

Infine, terremo traccia anche dell'operazione UPDATE creando un trigger DML che verrà attivato dopo aver eseguito un'operazione UPDATE sulla tabella padre. All'interno di questo trigger, recupereremo l'ultimo valore ID aggiornato da quella tabella padre dalla tabella virtuale inserita, tenendo in considerazione che il processo UPDATE viene eseguito eliminando il record e inserendo un nuovo record con i valori aggiornati, come nel CREATE TRIGGER Istruzione T-SQL di seguito:

CREATE TRIGGER AfterUPDATETrigger
ON TriggerDemo_Parent
AFTER UPDATE
AS
INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'UPDATE')
GO

Le tabelle e i trigger sono ora pronti per il nostro test. Se si tenta di inserire un nuovo record nella tabella padre utilizzando l'istruzione INSERT INTO T-SQL di seguito:

INSERT INTO TriggerDemo_Parent VALUES ('AAA','BBB',500)

Quindi controllando il piano di esecuzione generato eseguendo la precedente istruzione INSERT, vedrai che verranno eseguite due operazioni di inserimento, che interessano due tabelle; la tabella padre con i valori specificati nell'istruzione INSERT e la tabella della cronologia a causa dell'attivazione del trigger AFTER INSERT, come mostrato nel piano di esecuzione seguente:

È anche chiaro quando controlli i dati inseriti nelle tabelle padre e cronologia utilizzando le istruzioni SELECT seguenti:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Dove i valori specificati nell'istruzione INSERT verranno inseriti nella tabella padre e il log di inserimento che contiene l'ID del record inserito e l'operazione eseguita verrà inserito nella tabella della cronologia, come mostrato nel risultato seguente:

Ora, se provi ad aggiornare un record esistente nella tabella padre usando l'istruzione UPDATE T-SQL di seguito:

UPDATE TriggerDemo_Parent SET Emp_Salary=550 WHERE ID=1

E controlla il piano di esecuzione generato eseguendo la precedente istruzione UPDATE, vedrai che l'operazione di aggiornamento sarà seguita da un'operazione di inserimento che interessa due tabelle diverse; la tabella padre verrà aggiornata con il valore specificato nell'istruzione UPDATE e l'operazione di inserimento nella tabella della cronologia a causa dell'attivazione del trigger AFTER UPDATE, come mostrato nel piano di esecuzione seguente:

Controllo dei record della tabella padre e cronologia utilizzando le istruzioni SELECT seguenti:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Vedrai che l'istruzione di aggiornamento modificherà il valore Emp_Salary nella tabella padre con il valore specificato nell'istruzione UPDATE e il log di aggiornamento che contiene l'ID del record aggiornato e l'operazione eseguita verrà inserito nella tabella della cronologia, in quanto mostrato nel risultato di seguito:

Nell'ultimo scenario del trigger AFTER DML, terremo traccia dell'eliminazione di un record esistente dalla tabella padre utilizzando l'istruzione DELETE T-SQL di seguito:

DELETE FROM  TriggerDemo_Parent WHERE ID=1

Quindi controlla il piano di esecuzione generato eseguendo la precedente istruzione DELETE, vedrai che l'operazione DELETE sarà seguita dall'operazione di inserimento, interessando due tabelle diverse; la tabella padre da cui verrà eliminato il record con l'ID fornito nella clausola WHERE dell'istruzione DELETE e l'operazione di inserimento nella tabella della cronologia a causa dell'attivazione del trigger AFTER DELETE, come mostrato nel piano di esecuzione seguente:

Se controlli sia i record della tabella principale che quelli della tabella cronologica utilizzando le istruzioni SELECT di seguito:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Vedrai che il record con il valore ID uguale a 1 è stato eliminato dalla tabella padre fornita nell'istruzione DELETE e il registro di eliminazione che contiene l'ID del record eliminato e l'operazione eseguita verrà inserito nella tabella della cronologia , come mostrato nel risultato di seguito:

INVECE DI... Attivatore DML

Il secondo tipo di trigger DML è il trigger INSTEAD OF DML. Come accennato in precedenza, il trigger INSTEAD OF sovrascriverà l'istruzione dell'azione che attiva il trigger con l'istruzione fornita nel trigger. Si supponga di dover registrare le azioni DML che gli utenti stanno tentando di eseguire su una tabella specifica, senza consentire loro di eseguire tale azione. Le istruzioni CREATE TABLE T-SQL seguenti possono essere utilizzate per creare sia la tabella di origine che quella alternativa:

CREATE TABLE TriggerDemo_NewParent
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO


CREATE TABLE TriggerDemo_InsteadParent
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ParentID INT,
   PerformedAction VARCHAR (50),
  )
GO

Dopo aver creato le due tabelle, inseriremo un singolo record nella tabella di origine per la nostra demo utilizzando l'istruzione INSERT INTO di seguito:

INSERT INTO TriggerDemo_NewParent VALUES ('AA','BB', 500)

Per questa demo, creeremo tre trigger per sovrascrivere le operazioni INSERT, UPDATE ed DELETE. Il primo trigger verrà utilizzato per impedire qualsiasi operazione di inserimento nella tabella padre e nel registro che si modifica nella tabella alternativa. Il trigger viene creato utilizzando l'istruzione CREATE TRIGGER T-SQL di seguito:

CREATE TRIGGER InsteadOfInsertTrigger
ON TriggerDemo_NewParent
INSTEAD OF INSERT
AS
INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Trying to Insert new ID')
GO

Il secondo trigger viene utilizzato per impedire qualsiasi operazione di aggiornamento sulla tabella padre e sul registro che si modifica nella tabella alternativa. Questo trigger viene creato come segue:

CREATE TRIGGER InsteadOfUpdateTrigger
ON TriggerDemo_NewParent
INSTEAD OF UPDATE
AS
INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Trying to Update an existing ID')
GO

L'ultimo trigger verrà utilizzato per impedire qualsiasi operazione di eliminazione sulla tabella padre e il log che si modificano nella tabella alternativa. Questo trigger viene creato come segue:

CREATE TRIGGER InsteadOfDeleteTrigger
ON TriggerDemo_NewParent
INSTEAD OF DELETE
AS
INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1  inserted.ID FROM inserted), 'Trying to Delete an existing ID')
GO

I due tavoli ei tre trigger sono ora pronti. Se si tenta di inserire un nuovo valore nella tabella padre utilizzando l'istruzione INSERT INTO T-SQL di seguito:

INSERT INTO TriggerDemo_NewParent VALUES ('CCC','DDD',500)

Quindi controlla sia i record della tabella padre che quelli alternativi utilizzando le istruzioni SELECT seguenti:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

A causa del fatto che abbiamo il trigger INSTEAD OF INSERT nella tabella padre, vedrai dal risultato che nessun nuovo record viene inserito nella tabella padre e un registro per l'operazione di inserimento viene inserito nella tabella alternativa, come mostrato nel risultato qui sotto:

Tentativo di aggiornare un record esistente nella tabella padre utilizzando l'istruzione UPDATE T-SQL di seguito:

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Quindi controlla sia il record della tabella padre che quello alternativo utilizzando le istruzioni SELECT seguenti:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Vedrai dal risultato che il valore Emp_Salary del record con valore ID uguale a 1 dalla tabella padre non verrà modificato e il log per l'operazione di aggiornamento viene inserito nella tabella alternativa poiché ha il trigger INSTEAD OF UPDATE nella tabella padre, come mostrato nel risultato seguente:

Infine, se proviamo a eliminare un record esistente dalla tabella padre utilizzando l'istruzione DELETE T-SQL di seguito:

DELETE FROM  TriggerDemo_NewParent  WHERE ID=1

E controlla sia il record della tabella padre che quello alternativo usando le istruzioni SELECT di seguito:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Sarà chiaro dal risultato che il record con valore ID uguale a 1 dalla tabella padre non verrà eliminato e il log per l'operazione di eliminazione viene inserito nella tabella alternativa poiché ha il trigger INSTEAD OF DELETE nella tabella padre tabella, come mostrato nel risultato seguente:

DOPO... Attivazione DML con messaggi

Il trigger AFTER può essere utilizzato anche per generare un messaggio di avviso per un utente. In questo caso, la query sarà un messaggio informativo che non impedirà l'esecuzione dell'istruzione che attiva quel trigger. Rilasciamo il trigger INSTEAD OF UPDATE creato in precedenza e lo sostituiamo con un altro trigger AFTER UPDATE che genererà un errore di avviso dopo aver eseguito qualsiasi operazione di aggiornamento utilizzando le istruzioni T-SQL DROP/CREATE TRIGGER di seguito:

DROP TRIGGER InsteadOfUpdateTrigger
CREATE TRIGGER ReminderTrigger  
ON TriggerDemo_NewParent  
AFTER  UPDATE   
AS RAISERROR ('An Update is performed on the TriggerDemo_NewParent table', 16, 10);  
GO  

Se si tenta di aggiornare il valore Emp_Salary del dipendente con il valore ID uguale a 1 utilizzando l'istruzione UDPATE di seguito:

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Verrà visualizzato un messaggio di errore nei Messaggi scheda, che contiene il messaggio fornito nel trigger creato, come mostrato di seguito:

Controllo dei dati della tabella padre utilizzando l'istruzione SELECT di seguito:

SELECT * FROM TriggerDemo_NewParent

Vedrai dal risultato che l'Emp_Salary è stato aggiornato correttamente, come mostrato di seguito:

Se hai bisogno del trigger AFTER UPDATE per interrompere l'operazione di aggiornamento dopo aver visualizzato il messaggio di errore, il ROLLBACK l'istruzione può essere aggiunta al trigger per eseguire il rollback dell'operazione di aggiornamento che ha attivato quel trigger, ricordando che il trigger e l'istruzione che attiva il trigger verranno eseguiti nella stessa transazione. Questo può essere ottenuto utilizzando l'istruzione T-SQL ALTER TRIGGER, vedere:

ALTER TRIGGER ReminderTrigger  
ON TriggerDemo_NewParent  
AFTER  UPDATE   
AS RAISERROR ('An Update is performed on the TriggerDemo_NewParent table', 16, 10);  
ROLLBACK
GO  

Se provi ad aggiornare il valore Emp_Salary del dipendente con ID uguale a 1 utilizzando l'istruzione UPDATE di seguito:

UPDATE TriggerDemo_NewParent SET Emp_Salary=700 WHERE ID=1

Anche in questo caso, verrà visualizzato un messaggio di errore nei Messaggi scheda, ma questa volta l'operazione di aggiornamento verrà annullata completamente, come mostrato nei messaggi di errore seguenti:

Controllo del valore dalla tabella di origine utilizzando l'istruzione SELECT di seguito:

SELECT * FROM TriggerDemo_NewParent

Vedrai che il valore Emp_Salary non è cambiato, poiché il trigger AFTER UPDATE ha eseguito il rollback della transazione complessiva dopo aver generato il messaggio di errore, come mostrato nel risultato della tabella seguente:

Svantaggi dei trigger

Con tutti i vantaggi menzionati dei trigger di SQL Server, i trigger aumentano la complessità del database. Se il trigger è progettato in modo errato o utilizzato in modo eccessivo, causerà gravi problemi di prestazioni, come sessioni bloccate, a causa dell'estensione della durata della transazione per un tempo più lungo, sovraccarico sul sistema dovuto all'esecuzione ogni volta che un INSERT, UPDATE o L'azione DELETE viene eseguita o potrebbe causare problemi di perdita di dati. Inoltre, non è facile visualizzare e tracciare i trigger del database, soprattutto se non c'è documentazione a riguardo in quanto è invisibile agli sviluppatori e alle applicazioni.

Alternative attivate... Applica integrità

Se si rileva che i trigger stanno danneggiando le prestazioni dell'istanza di SQL Server, è necessario sostituirli con altre soluzioni. Ad esempio, anziché utilizzare i trigger per imporre l'integrità dell'entità, dovrebbe essere applicata al livello più basso utilizzando i vincoli PRIMARY KEY e UNIQUE. Lo stesso si applica all'integrità del dominio che dovrebbe essere applicata tramite i vincoli CHECK e all'integrità referenziale che dovrebbe essere applicata tramite i vincoli FOREIGN KEY. Puoi utilizzare i trigger DML solo se le funzionalità supportate da un vincolo specifico non possono soddisfare i requisiti dell'applicazione.

Confrontiamo tra l'applicazione dell'integrità del dominio utilizzando i trigger DML e l'utilizzo dei vincoli CHECK. Si supponga di dover imporre l'inserimento di valori positivi solo nella colonna Emp_Salary. Inizieremo con la creazione di una tabella semplice utilizzando l'istruzione CREATE TABLE T-SQL di seguito:

CREATE TABLE EmployeeSalaryTrigger
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO

Quindi definisci il trigger DML AFTER INSERT che ti assicura di inserire un valore positivo nella colonna Emp_Salary eseguendo il rollback della transazione se un utente inserisce un valore di stipendio negativo, utilizzando l'istruzione CREATE TRIGGER T-SQL di seguito:

CREATE TRIGGER TRGR_EmployeeSalary ON EmployeeSalaryTrigger 
AFTER INSERT 
AS
DECLARE @EmpSal AS INT
SET @EmpSal = (SELECT TOP 1 inserted.Emp_Salary FROM inserted)
IF @EmpSal<0
BEGIN 
 RAISERROR  ('Cannot insert negative salary',16,10);
  ROLLBACK
END

A scopo di confronto, creeremo un'altra tabella semplice, con lo stesso schema, e definiremo un vincolo CHECK all'interno dell'istruzione CREATE TABLE per accettare solo valori positivi nella colonna Emp_Salary, come mostrato di seguito:

CREATE TABLE EmployeeSalaryConstraint
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT CONSTRAINT EmpSal CHECK (Emp_Salary >=0)
  )
GO

Se provi a inserire il record seguente che contiene un valore Emp_Salary negativo nella prima tabella che ha un trigger predefinito, utilizzando l'istruzione INSERT INTO di seguito:

INSERT INTO EmployeeSalaryTrigger VALUES('Ali', 'Fadi',-4)
GO

L'istruzione INSERT non riuscirà generando un messaggio di errore che mostra che non è possibile inserire un valore negativo nella colonna Emp_Salary e ripristinare la transazione complessiva a causa di un trigger AFTER INSERT, come mostrato nel messaggio di errore seguente:

Inoltre, se tenti di inserire lo stesso record che contiene un valore Emp_Salary negativo nella seconda tabella che ha un vincolo CHECK predefinito utilizzando l'istruzione INSERT INTO di seguito:

INSERT INTO EmployeeSalaryConstraint VALUES ('Ali', 'Fadi',-4)

L'istruzione INSERT non riuscirà di nuovo mostrando che stai tentando di inserire il valore che è in conflitto con la condizione di vincolo CHECK, come mostrato nel messaggio di errore seguente:

Dai risultati precedenti, puoi vedere che entrambi i metodi di vincolo trigger e CHECK raggiungono l'obiettivo impedendoti di inserire valori Emp_Salary negativi. Ma quale è meglio? Confrontiamo le prestazioni dei due metodi controllando il peso del piano di esecuzione per ciascuno. Dai piani di esecuzione generati dopo l'esecuzione delle due query, vedrai che il peso del metodo di attivazione è tre volte il peso del metodo di vincolo CHECK, come mostrato nel confronto del piano di esecuzione di seguito:

Inoltre, per confrontare il tempo di esecuzione consumato da ciascuno, eseguiamo ciascuno 1000 volte utilizzando le istruzioni T-SQL seguenti:

INSERT INTO EmployeeSalaryTrigger VALUES('Ali', 'Fadi',-4)
GO 10000  
INSERT INTO EmployeeSalaryConstraint VALUES ('Ali', 'Fadi',-4)
GO 10000 

Vedrai che il primo metodo che utilizza il trigger impiegherà circa 31 ms da eseguire completamente, dove il secondo metodo che utilizza il vincolo CHECK impiegherà solo 17 ms , ovvero circa 0,5 volte richiesto nel metodo che utilizza il trigger. Ciò è dovuto al fatto che il trigger estenderà la durata della transazione e eseguirà il rollback della query che attiva il trigger dopo l'esecuzione quando viene rilevata una violazione dell'integrità, causando un degrado delle prestazioni a causa del processo di rollback. Il caso è diverso quando si utilizza il vincolo CHECK, dove il vincolo farà il suo lavoro prima di apportare qualsiasi modifica ai dati, senza richiedere il rollback in caso di violazione.

Alternative di trigger... Controllo

Come accennato in precedenza, i trigger possono essere utilizzati anche per controllare e tenere traccia delle modifiche eseguite su una tabella specifica. Se questo metodo di controllo provoca un degrado delle prestazioni nell'istanza di SQL Server, puoi facilmente sostituirlo con OUTPUT clausola. La clausola OUTPUT restituisce informazioni su ciascuna riga interessata dall'operazione INSERT, UPDATE o DELETE, sotto forma di un messaggio di conferma o di un valore che può essere inserito nella tabella storica. Il metodo della clausola OUTPUT ci fornisce anche un maggiore controllo sul codice eseguito, poiché verrà aggiunto all'istruzione di inserimento, modifica o eliminazione dei dati stessa ogni volta che lo desideri, di fronte al trigger che verrà sempre eseguito.

Confrontiamo tra la registrazione dell'inserimento e la modifica dei dati nella tabella della cronologia utilizzando i trigger DML e l'utilizzo della clausola OUTPUT. Inizieremo con la creazione delle tabelle di produzione e cronologia seguenti utilizzando l'istruzione CREATE TABLE T-SQL di seguito:

CREATE TABLE TriggerDemo_Prod
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO


CREATE TABLE TriggerDemo_ProdHistory
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ProdID INT,
   ProdSalary INT,
   TS DATETIME,
  )
GO

Una volta che entrambe le tabelle sono state create correttamente, creeremo il trigger AFTER INSERT, UPDATE DML che scriverà un record nella tabella della cronologia se viene inserita una nuova riga nella tabella di produzione o se un record esistente viene modificato utilizzando l'istruzione CREATE TRIGGER T-SQL sotto:

CREATE TRIGGER ProdHistory
ON TriggerDemo_Prod
AFTER INSERT, UPDATE
AS
INSERT INTO TriggerDemo_ProdHistory  VALUES ( (SELECT TOP 1  inserted.ID FROM inserted),(SELECT TOP 1  inserted.Emp_Salary FROM inserted), GETDATE())
GO

Per confrontare la registrazione delle modifiche utilizzando il metodo trigger e la clausola OUTPUT, dobbiamo creare due nuove tabelle semplici, la produzione e la cronologia, con lo stesso schema delle due tabelle precedenti, ma questa volta senza definire un trigger, utilizzando il CREATE TABLE Istruzioni T-SQL di seguito:

CREATE TABLE OutputDemo_Prod
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   Emp_First_name VARCHAR (50),
   Emp_Last_name VARCHAR (50),
   Emp_Salary INT 
  )
GO


CREATE TABLE OutputDemo_ProdHistory
(
   ID INT IDENTITY (1,1) PRIMARY KEY,
   ProdID INT,
   ProdSalary INT,
   TS DATETIME,
  )
  
GO

Ora i quattro tavoli sono pronti per il test. Inseriremo un record nella prima tabella di produzione che ha un trigger utilizzando l'istruzione INSERT INTO T-SQL di seguito:

INSERT INTO TriggerDemo_Prod values('AA','BB', 750)
GO 

Quindi inseriremo lo stesso record nella seconda tabella di produzione utilizzando la clausola OUTPUT. La seguente istruzione INSERT INTO agirà come due istruzioni di inserimento; la prima inserirà lo stesso record nella tabella di produzione e la seconda istruzione di inserimento accanto alla clausola OUTPUT inserirà il log di inserimento nella tabella della cronologia:

INSERT INTO OutputDemo_Prod  OUTPUT inserted.ID, inserted.Emp_Salary, GETDATE() 
INTO OutputDemo_ProdHistory	values('AA','BB', 750)
GO 

Controllando i dati inseriti nelle quattro tabelle di produzione e cronologia, vedrai che entrambi i metodi, trigger e OUTPUT, scriveranno lo stesso log nella tabella della cronologia con successo e allo stesso modo, come mostrato nel risultato seguente:

Dai piani di esecuzione generati dopo l'esecuzione delle due query, vedrai che il peso del metodo di attivazione è di circa (21%+36%) 57% del peso complessivo, dove il peso del metodo OUTPUT è di circa il 43% , con una piccola differenza di peso, come mostrato nel confronto dei piani di esecuzione di seguito:

La differenza di prestazioni è evidente quando si confronta il tempo di esecuzione consumato da ciascun metodo, dove la registrazione delle modifiche utilizzando il metodo di attivazione consumerà (114+125) 239 ms da eseguire completamente e il metodo che utilizza il metodo della clausola OUTPUT consuma solo 5 ms , che è il 2% del tempo utilizzato nel metodo di attivazione, come mostrato chiaramente dalle statistiche temporali di seguito:

È chiaro ora dal risultato precedente che l'utilizzo del metodo OUTPUT è migliore rispetto all'utilizzo di trigger per il controllo delle modifiche.

Link utili:

  • CREA TRIGGER (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
  • Trigger DML https://docs.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers
  • Trigger DDL https://docs.microsoft.com/en-us/sql/relational-databases/triggers/ddl-triggers
  • Clausola OUTPUT (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql