Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Déclencheur SQL Server :compréhension et alternatives

Le déclencheur SQL Server est un type spécial de procédures stockées qui est automatiquement exécutée lorsqu'un événement se produit dans un serveur de base de données spécifique. SQL Server nous fournit deux principaux types de déclencheurs :le DML Déclencheurs et DDL déclencheurs. Les déclencheurs DDL seront déclenchés en réponse à différents événements DDL (Data Definition Language), tels que l'exécution d'instructions CREATE, ALTER, DROP, GRANT, DENY et REVOKE T-SQL. Le déclencheur DDL peut répondre aux actions DDL en empêchant ces modifications d'affecter la base de données, effectuer une autre action en réponse à ces actions DDL ou enregistrer ces modifications qui sont exécutées sur la base de données.

Le déclencheur SQL Server DML est un type spécial de procédures stockées conçu pour effectuer une séquence d'actions sur une table de base de données, à laquelle le déclencheur est attaché, lorsqu'un événement DML (Data Manipulation Language), tel que INSERT, UPDATE ou DELETE action, se produit pour modifier le contenu des tables ou des vues de la base de données, que les lignes de la table soient affectées ou non. Les déclencheurs diffèrent des procédures stockées en ce sens qu'ils sont déclenchés automatiquement lorsqu'une modification de données prédéfinie se produit. Les déclencheurs DML peuvent être utilisés pour maintenir l'intégrité des données et appliquer les règles métier de l'entreprise, tout comme la fonctionnalité de vérification de table et de contraintes de clés étrangères, en effectuant des processus d'audit et d'autres actions post DML. Vous pouvez utiliser les déclencheurs DML pour interroger d'autres tables et effectuer des requêtes T-SQL complexes.

Si le déclencheur est activé, un type spécial de tables virtuelles appelé Inséré et Supprimé des tables seront utilisées pour conserver les valeurs des données avant et après la modification. L'instruction de déclencheur fonctionnera dans le cadre de la même transaction qui déclenche ce déclencheur. Cela signifie que la transaction ne sera pas validée complètement tant que l'instruction de déclenchement ne sera pas terminée avec succès. D'autre part, la transaction sera annulée si l'instruction de déclenchement échoue.

Il existe deux types de déclencheurs DML :APRÈS ou POUR déclencheur et AU LIEU DE gâchette. Le déclencheur AFTER sera déclenché et exécuté après avoir effectué l'action INSERT, UPDATE ou DELETE qui l'a déclenché avec succès. En outre, toutes les actions référentielles en cascade et les vérifications de contraintes doivent réussir avant de déclencher le déclencheur. Le déclencheur AFTER peut être défini au niveau de la table uniquement sans possibilité de le définir sur les vues. Le déclencheur INSTEAD OF est utilisé pour remplacer l'instruction de l'action qui déclenche le déclencheur par l'instruction fournie dans le déclencheur, annulant cette instruction après avoir déclenché une erreur lorsque quelqu'un tente d'effectuer une action qui enfreint une politique spécifique, telle que la mise à jour une colonne financière critique ou écrire le changement dans un tableau d'audit avant d'effectuer le changement. Le déclencheur INSTEAD OF vous permet d'INSÉRER, de METTRE À JOUR ou de SUPPRIMER des données à partir des vues qui font référence à des données de plusieurs tables, en plus de la possibilité de rejeter une partie d'une requête par lots et d'exécuter une autre partie de ce lot avec succès. Le déclencheur INSTEAD OF ne peut pas être utilisé avec les vues modifiables qui ont WITH CHECK OPTION et dans les tables avec une relation référentielle qui spécifie des actions en cascade sur DELETE ou UPDATE.

Après avoir discuté théoriquement des déclencheurs, nous commencerons à montrer ce dont nous discutons pratiquement. Dans les démos à venir, nous montrerons les différentes situations dans lesquelles nous pouvons tirer parti des déclencheurs SQL Server.

APRÈS… Déclencheur DML

Supposons que nous devions suivre les actions DML effectuées sur une table spécifique et écrire ces journaux dans une table d'historique, où l'ID de l'enregistrement inséré, mis à jour ou supprimé et l'action effectuée seront écrits dans la table d'historique. Les instructions CREATE TABLE T-SQL ci-dessous peuvent être utilisées pour créer à la fois les tables source et historique :

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

Pour suivre l'opération INSERT, nous allons créer un déclencheur DML qui sera déclenché après avoir effectué une opération INSERT sur la table parent. Ce déclencheur récupère la dernière valeur d'ID insérée dans cette table parent à partir de la table virtuelle insérée, comme dans l'instruction CREATE TRIGGER T-SQL ci-dessous :

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

Le suivi de l'opération DELETE peut être réalisé en créant un déclencheur DML qui est déclenché après avoir effectué l'opération DELETE sur la table parent. Encore une fois, le déclencheur récupère la valeur d'ID du dernier enregistrement supprimé de cette table parent à partir de la table virtuelle supprimée, comme dans l'instruction CREATE TRIGGER T-SQL ci-dessous :

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

Enfin, nous suivrons également l'opération UPDATE en créant un déclencheur DML qui sera déclenché après avoir effectué une opération UPDATE sur la table parent. Dans ce déclencheur, nous allons récupérer la dernière valeur d'ID mise à jour de cette table parent à partir de la table insérée virtuelle, en tenant compte du fait que le processus UPDATE est effectué en supprimant l'enregistrement et en insérant un nouvel enregistrement avec les valeurs mises à jour, comme dans le CREATE TRIGGER Instruction T-SQL ci-dessous :

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

Les tables et les déclencheurs sont maintenant prêts pour nos tests. Si vous essayez d'insérer un nouvel enregistrement dans la table parent à l'aide de l'instruction INSERT INTO T-SQL ci-dessous :

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

Ensuite, en vérifiant le plan d'exécution généré par l'exécution de l'instruction INSERT précédente, vous verrez que deux opérations d'insertion seront effectuées, affectant deux tables ; la table parent avec les valeurs spécifiées dans l'instruction INSERT et la table d'historique en raison du déclenchement du déclencheur AFTER INSERT, comme indiqué dans le plan d'exécution ci-dessous :

Il est également clair lorsque vous vérifiez les données insérées dans les tables parent et historique à l'aide des instructions SELECT ci-dessous :

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Où les valeurs spécifiées dans l'instruction INSERT seront insérées dans la table parent, et le journal d'insertion contenant l'ID de l'enregistrement inséré et l'opération effectuée seront insérés dans la table d'historique, comme indiqué dans le résultat ci-dessous :

Maintenant, si vous essayez de mettre à jour un enregistrement existant dans la table parent à l'aide de l'instruction UPDATE T-SQL ci-dessous :

UPDATE TriggerDemo_Parent SET Emp_Salary=550 WHERE ID=1

Et vérifiez le plan d'exécution généré en exécutant l'instruction UPDATE précédente, vous verrez que l'opération de mise à jour sera suivie d'une opération d'insertion affectant deux tables différentes ; la table parent sera mise à jour avec la valeur spécifiée dans l'instruction UPDATE et l'opération d'insertion dans la table d'historique en raison du déclenchement du déclencheur AFTER UPDATE, comme indiqué dans le plan d'exécution ci-dessous :

Vérification des enregistrements de la table parent et de l'historique à l'aide des instructions SELECT ci-dessous :

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Vous verrez que l'instruction de mise à jour modifiera la valeur Emp_Salary dans la table parent avec la valeur spécifiée dans l'instruction UPDATE, et le journal de mise à jour qui contient l'ID de l'enregistrement mis à jour et l'opération effectuée sera inséré dans la table d'historique, comme indiqué dans le résultat ci-dessous :

Dans le dernier scénario du déclencheur AFTER DML, nous suivrons la suppression d'un enregistrement existant de la table parent à l'aide de l'instruction DELETE T-SQL ci-dessous :

DELETE FROM  TriggerDemo_Parent WHERE ID=1

Vérifiez ensuite le plan d'exécution généré en exécutant l'instruction DELETE précédente, vous verrez que l'opération DELETE sera suivie de l'opération d'insertion, affectant deux tables différentes ; la table parent à partir de laquelle l'enregistrement avec l'ID fourni dans la clause WHERE de l'instruction DELETE sera supprimé et l'opération d'insertion dans la table d'historique en raison du déclenchement du déclencheur AFTER DELETE, comme indiqué dans le plan d'exécution ci-dessous :

Si vous vérifiez à la fois les enregistrements de la table parent et historique à l'aide des instructions SELECT ci-dessous :

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Vous verrez que l'enregistrement avec la valeur d'ID égale à 1 a été supprimé de la table parent fournie dans l'instruction DELETE, et le journal de suppression contenant l'ID de l'enregistrement supprimé et l'opération effectuée sera inséré dans la table d'historique. , comme indiqué dans le résultat ci-dessous :

AU LIEU DE… Déclencheur DML

Le deuxième type de déclencheurs DML est le déclencheur INSTEAD OF DML. Comme mentionné précédemment, le déclencheur INSTEAD OF remplacera l'instruction de l'action qui déclenche le déclencheur par l'instruction fournie dans le déclencheur. Supposons que nous devions enregistrer les actions DML que les utilisateurs tentent d'effectuer sur une table spécifique, sans leur permettre d'effectuer cette action. Les instructions CREATE TABLE T-SQL ci-dessous peuvent être utilisées pour créer à la fois les tables source et alternative :

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

Après avoir créé les deux tables, nous allons insérer un seul enregistrement dans la table source de notre démo à l'aide de l'instruction INSERT INTO ci-dessous :

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

Pour cette démo, nous allons créer trois déclencheurs pour remplacer les opérations INSERT, UPDATE et DELETE. Le premier déclencheur sera utilisé pour empêcher toute opération d'insertion sur la table parent et le journal qui changent dans la table alternative. Le déclencheur est créé à l'aide de l'instruction CREATE TRIGGER T-SQL ci-dessous :

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

Le deuxième déclencheur est utilisé pour empêcher toute opération de mise à jour sur la table parent et le journal qui changent dans la table alternative. Ce déclencheur est créé comme ci-dessous :

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

Le dernier déclencheur sera utilisé pour empêcher toute opération de suppression sur la table parent et le journal qui se transforment en table alternative. Ce déclencheur est créé comme suit :

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

Les deux tables et les trois déclencheurs sont prêts maintenant. Si vous essayez d'insérer une nouvelle valeur dans la table parent à l'aide de l'instruction INSERT INTO T-SQL ci-dessous :

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

Vérifiez ensuite à la fois les enregistrements de la table parent et alternative à l'aide des instructions SELECT ci-dessous :

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

En raison du fait que nous avons le déclencheur INSTEAD OF INSERT dans la table parent, vous verrez à partir du résultat qu'aucun nouvel enregistrement n'est inséré dans la table parent, et un journal pour l'opération d'insertion est inséré dans la table alternative, comme indiqué dans le résultat ci-dessous :

Tentative de mise à jour d'un enregistrement existant dans la table parent à l'aide de l'instruction UPDATE T-SQL ci-dessous :

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Ensuite, vérifiez à la fois les enregistrements de la table parent et alternative à l'aide des instructions SELECT ci-dessous :

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Vous verrez à partir du résultat que la valeur Emp_Salary de l'enregistrement avec la valeur ID égale à 1 de la table parent ne sera pas modifiée, et le journal de l'opération de mise à jour est inséré dans la table alternative en raison du déclencheur INSTEAD OF UPDATE dans la table parent, comme indiqué dans le résultat ci-dessous :

Enfin, si nous essayons de supprimer un enregistrement existant de la table parent à l'aide de l'instruction DELETE T-SQL ci-dessous :

DELETE FROM  TriggerDemo_NewParent  WHERE ID=1

Et vérifiez à la fois les enregistrements de la table parent et alternative à l'aide des instructions SELECT ci-dessous :

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Il ressort clairement du résultat que l'enregistrement avec la valeur d'ID égale à 1 de la table parent ne sera pas supprimé, et le journal de l'opération de suppression est inséré dans la table alternative en raison de la présence du déclencheur INSTEAD OF DELETE dans le parent tableau, comme indiqué dans le résultat ci-dessous :

APRÈS… Déclencheur DML avec messages

Le déclencheur AFTER peut également être utilisé pour générer un message d'avertissement pour un utilisateur. Dans ce cas, la requête sera un message d'information qui n'empêchera pas l'exécution de l'instruction qui déclenche ce déclencheur. Laissons tomber le déclencheur INSTEAD OF UPDATE précédemment créé et remplaçons-le par un autre déclencheur AFTER UPDATE qui déclenchera une erreur d'avertissement après avoir effectué toute opération de mise à jour à l'aide des instructions T-SQL DROP/CREATE TRIGGER ci-dessous :

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  

Si vous essayez de mettre à jour la valeur Emp_Salary de l'employé avec la valeur ID égale à 1 à l'aide de l'instruction UDPATE ci-dessous :

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Un message d'erreur sera généré dans les Messages , qui contient le message fourni dans le déclencheur créé, comme indiqué ci-dessous :

Vérification des données de la table parent à l'aide de l'instruction SELECT ci-dessous :

SELECT * FROM TriggerDemo_NewParent

Vous verrez d'après le résultat que Emp_Salary est mis à jour avec succès, comme indiqué ci-dessous :

Si vous avez besoin du déclencheur AFTER UPDATE pour arrêter l'opération de mise à jour après avoir généré le message d'erreur, le ROLLBACK peut être ajoutée au déclencheur afin d'annuler l'opération de mise à jour qui a déclenché ce déclencheur, en rappelant que le déclencheur et l'instruction qui déclenche le déclencheur seront exécutés dans la même transaction. Ceci peut être réalisé à l'aide de l'instruction ALTER TRIGGER T-SQL, voir :

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

Si vous essayez de mettre à jour la valeur Emp_Salary de l'employé avec l'ID égal à 1 à l'aide de l'instruction UPDATE ci-dessous :

UPDATE TriggerDemo_NewParent SET Emp_Salary=700 WHERE ID=1

Encore une fois, un message d'erreur s'affichera dans les Messages , mais cette fois, l'opération de mise à jour sera complètement annulée, comme indiqué dans les messages d'erreur ci-dessous :

Vérification de la valeur de la table source à l'aide de l'instruction SELECT ci-dessous :

SELECT * FROM TriggerDemo_NewParent

Vous verrez que la valeur Emp_Salary n'a pas changé, car le déclencheur AFTER UPDATE a annulé la transaction globale après avoir généré le message d'erreur, comme indiqué dans le résultat du tableau ci-dessous :

Inconvénients du déclencheur

Avec tous les avantages mentionnés des déclencheurs SQL Server, les déclencheurs augmentent la complexité de la base de données. Si le déclencheur est mal conçu ou surutilisé, cela entraînera des problèmes de performances majeurs, tels que des sessions bloquées, en raison de la prolongation de la durée de vie de la transaction, une surcharge supplémentaire sur le système en raison de son exécution à chaque fois qu'un INSERT, UPDATE ou L'action SUPPRIMER est effectuée ou cela peut entraîner des problèmes de perte de données. De plus, il n'est pas facile de visualiser et de tracer les déclencheurs de la base de données, surtout s'il n'y a pas de documentation à ce sujet car il est invisible pour les développeurs et les applications.

Alternatives de déclenchement… Imposer l'intégrité

S'il s'avère que les déclencheurs nuisent aux performances de votre instance SQL Server, vous devez les remplacer par d'autres solutions. Par exemple, plutôt que d'utiliser les déclencheurs pour appliquer l'intégrité de l'entité, celle-ci doit être appliquée au niveau le plus bas en utilisant les contraintes PRIMARY KEY et UNIQUE. La même chose s'applique à l'intégrité du domaine qui doit être appliquée via les contraintes CHECK, et à l'intégrité référentielle qui doit être appliquée via les contraintes FOREIGN KEY. Vous pouvez utiliser les déclencheurs DML uniquement si les fonctionnalités prises en charge par une contrainte spécifique ne peuvent pas répondre aux exigences de votre application.

Comparons entre l'application de l'intégrité du domaine à l'aide de déclencheurs DML et l'utilisation des contraintes CHECK. Supposons que nous devions imposer l'insertion de valeurs positives uniquement dans la colonne Emp_Salary. Nous allons commencer par créer une table simple à l'aide de l'instruction CREATE TABLE T-SQL ci-dessous :

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

Définissez ensuite le déclencheur AFTER INSERT DML qui garantit que vous insérez une valeur positive dans la colonne Emp_Salary en annulant la transaction si un utilisateur insère une valeur de salaire négative, à l'aide de l'instruction CREATE TRIGGER T-SQL ci-dessous :

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

À des fins de comparaison, nous allons créer une autre table simple, avec le même schéma, et définir une contrainte CHECK dans l'instruction CREATE TABLE pour n'accepter que des valeurs positives dans la colonne Emp_Salary, comme indiqué ci-dessous :

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

Si vous essayez d'insérer l'enregistrement ci-dessous qui contient une valeur Emp_Salary négative dans la première table qui a un déclencheur prédéfini, en utilisant l'instruction INSERT INTO ci-dessous :

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

L'instruction INSERT échouera à générer un message d'erreur indiquant que vous ne pouvez pas insérer une valeur négative dans la colonne Emp_Salary et annuler la transaction globale en raison d'un déclencheur AFTER INSERT, comme indiqué dans le message d'erreur ci-dessous :

De plus, si vous essayez d'insérer le même enregistrement qui contient une valeur Emp_Salary négative dans la deuxième table qui a une contrainte CHECK prédéfinie à l'aide de l'instruction INSERT INTO ci-dessous :

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

L'instruction INSERT échouera à nouveau, indiquant que vous essayez d'insérer la valeur qui entre en conflit avec la condition de contrainte CHECK, comme indiqué dans le message d'erreur ci-dessous :

D'après les résultats précédents, vous voyez que les méthodes de déclenchement et de contrainte CHECK atteignent l'objectif en vous empêchant d'insérer des valeurs Emp_Salary négatives. Mais lequel est le meilleur ? Comparons les performances des deux méthodes en vérifiant le poids du plan d'exécution pour chacune. À partir des plans d'exécution générés après l'exécution des deux requêtes, vous verrez que le poids de la méthode de déclenchement est trois fois le poids de la méthode de contrainte CHECK, comme indiqué dans la comparaison de plan d'exécution ci-dessous :

De plus, pour comparer le temps d'exécution consommé par chacun, exécutons chacun 1000 fois en utilisant les instructions T-SQL ci-dessous :

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

Vous verrez que la première méthode utilisant le déclencheur prendra environ 31 ms à exécuter complètement, où la deuxième méthode qui utilise la contrainte CHECK ne prendra que 17 ms , soit environ 0,5 le temps requis dans la méthode utilisant le déclencheur. Cela est dû au fait que le déclencheur prolongera la durée de vie de la transaction et annulera la requête qui déclenche le déclencheur après l'avoir exécuté lorsqu'une violation d'intégrité est détectée, entraînant une dégradation des performances en raison du processus d'annulation. Le cas est différent lors de l'utilisation de la contrainte CHECK, où la contrainte fera son travail avant de faire toute modification dans les données, ne nécessitant aucune annulation en cas de violation.

Alternatives de déclenchement… Audit

Comme nous l'avons mentionné précédemment, les déclencheurs peuvent également être utilisés pour auditer et suivre les modifications effectuées sur une table spécifique. Si cette méthode d'audit provoque une dégradation des performances de votre instance SQL Server, vous pouvez facilement la remplacer par la OUTPUT clause. La clause OUTPUT retourne des informations sur chaque ligne concernée par l'opération INSERT, UPDATE ou DELETE, sous la forme d'un message de confirmation ou d'une valeur pouvant être insérée dans la table historique. La méthode de la clause OUTPUT nous offre également plus de contrôle sur le code exécuté, car il sera ajouté à l'instruction d'insertion, de modification ou de suppression de données elle-même quand vous le souhaitez, contrairement au déclencheur qui sera toujours exécuté.

Comparons entre la journalisation de l'insertion et de la modification des données dans la table d'historique à l'aide de déclencheurs DML et à l'aide de la clause OUTPUT. Nous allons commencer par créer les tables de production et d'historique ci-dessous à l'aide de l'instruction CREATE TABLE T-SQL ci-dessous :

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

Une fois les deux tables créées avec succès, nous créerons le déclencheur AFTER INSERT, UPDATE DML qui écrira un enregistrement dans la table d'historique si une nouvelle ligne est insérée dans la table de production ou si un enregistrement existant est modifié à l'aide de l'instruction CREATE TRIGGER T-SQL. ci-dessous :

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

Pour comparer la journalisation des modifications à l'aide de la méthode de déclenchement et de la clause OUTPUT, nous devons créer deux nouvelles tables simples, les tables de production et d'historique, avec le même schéma que les deux tables précédentes, mais cette fois sans définir de déclencheur, en utilisant la Instructions CREATE TABLE T-SQL ci-dessous :

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

Maintenant, les quatre tables sont prêtes pour le test. Nous allons insérer un enregistrement dans la première table de production qui a un déclencheur à l'aide de l'instruction INSERT INTO T-SQL ci-dessous :

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

Ensuite, nous allons insérer le même enregistrement dans la deuxième table de production à l'aide de la clause OUTPUT. L'instruction INSERT INTO ci-dessous agira comme deux instructions d'insertion ; la première insèrera le même enregistrement dans la table de production et la deuxième instruction d'insertion à côté de la clause OUTPUT insèrera le journal d'insertion dans la table d'historique :

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

En vérifiant les données insérées dans les quatre tables de production et d'historique, vous verrez que les deux méthodes, les méthodes trigger et OUTPUT, écriront le même journal dans la table d'historique avec succès et de la même manière, comme indiqué dans le résultat ci-dessous :

À partir des plans d'exécution générés après l'exécution des deux requêtes, vous verrez que le poids de la méthode de déclenchement est d'environ (21 % + 36 %) 57 % du poids total, où le poids de la méthode OUTPUT est d'environ 43 % , avec une légère différence de poids, comme le montre la comparaison des plans d'exécution ci-dessous :

La différence de performances est claire lorsque l'on compare le temps d'exécution consommé par chaque méthode, où la journalisation des modifications à l'aide de la méthode de déclenchement consommera (114+125) 239 ms à exécuter complètement, et la méthode qui utilise la méthode de la clause OUTPUT ne consomme que 5 ms , soit 2 % du temps utilisé dans la méthode de déclenchement, comme indiqué clairement dans les statistiques de temps ci-dessous :

Il ressort clairement du résultat précédent que l'utilisation de la méthode OUTPUT est préférable à l'utilisation de déclencheurs pour l'audit des modifications.

Liens utiles :

  • CRÉER UN DÉCLENCHEUR (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
  • Déclencheurs DML https://docs.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers
  • Déclencheurs DDL https://docs.microsoft.com/en-us/sql/relational-databases/triggers/ddl-triggers
  • Clause OUTPUT (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql