Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SQL Server-Trigger:Verständnis und Alternativen

Der SQL Server-Trigger ist eine spezielle Art gespeicherter Prozeduren, die automatisch ausgeführt werden, wenn ein Ereignis auf einem bestimmten Datenbankserver auftritt. SQL Server stellt uns zwei Haupttypen von Triggern zur Verfügung:die DML Trigger und die DDL löst aus. Die DDL-Trigger werden als Reaktion auf verschiedene DDL-Ereignisse (Data Definition Language) ausgelöst, z. B. das Ausführen von CREATE-, ALTER-, DROP-, GRANT-, DENY- und REVOKE-T-SQL-Anweisungen. Der DDL-Trigger kann auf die DDL-Aktionen reagieren, indem er verhindert, dass sich diese Änderungen auf die Datenbank auswirken, als Reaktion auf diese DDL-Aktionen eine andere Aktion ausführen oder diese Änderungen aufzeichnen, die für die Datenbank ausgeführt werden.

Der SQL Server-DML-Trigger ist eine spezielle Art gespeicherter Prozeduren, die entwickelt wurden, um eine Abfolge von Aktionen für eine Datenbanktabelle auszuführen, an die der Trigger angehängt ist, wenn ein DML-Ereignis (Data Manipulation Language) wie INSERT, UPDATE oder DELETE erfolgt Aktion, um den Inhalt der Datenbanktabellen oder -ansichten zu ändern, unabhängig davon, ob die Tabellenzeilen betroffen sind oder nicht. Die Trigger unterscheiden sich von den gespeicherten Prozeduren darin, dass die Trigger automatisch ausgelöst werden, wenn eine vordefinierte Datenänderung auftritt. Die DML-Trigger können verwendet werden, um die Datenintegrität aufrechtzuerhalten und Geschäftsregeln des Unternehmens durchzusetzen, ebenso wie die Funktionalität für Tabellenprüfungen und Fremdschlüsseleinschränkungen, indem Prüfprozesse und andere Post-DML-Aktionen durchgeführt werden. Sie können die DML-Trigger verwenden, um andere Tabellen abzufragen und komplexe T-SQL-Abfragen durchzuführen.

Wenn der Trigger ausgelöst wird, wird ein spezieller Typ virtueller Tabellen namens Inserted angezeigt und gelöscht Tabellen werden verwendet, um die Datenwerte vor und nach der Änderung beizubehalten. Die Trigger-Anweisung funktioniert im Rahmen derselben Transaktion, die diesen Trigger auslöst. Das bedeutet, dass die Transaktion nicht vollständig festgeschrieben wird, bis die Trigger-Anweisung erfolgreich abgeschlossen ist. Andererseits wird die Transaktion zurückgesetzt, wenn die Trigger-Anweisung fehlschlägt.

Es gibt zwei Arten von DML-Triggern:AFTER oder FÜR Auslöser und STATT VON Abzug. Der AFTER-Trigger wird ausgelöst und ausgeführt, nachdem die INSERT-, UPDATE- oder DELETE-Aktion ausgeführt wurde, die ihn erfolgreich ausgelöst hat. Außerdem sollten alle referenziellen Kaskadenaktionen und Einschränkungsprüfungen erfolgreich sein, bevor der Trigger ausgelöst wird. Der AFTER-Trigger kann nur auf Tabellenebene definiert werden, ohne die Möglichkeit, ihn auf Ansichten zu definieren. Der INSTEAD OF-Trigger wird verwendet, um die Anweisung der Aktion, die den Trigger auslöst, mit der im Trigger bereitgestellten Anweisung zu überschreiben und diese Anweisung zurückzusetzen, nachdem ein Fehler ausgelöst wurde, wenn jemand versucht, eine Aktion auszuführen, die gegen eine bestimmte Richtlinie verstößt, z. B. Aktualisieren eine kritische Finanzspalte oder das Schreiben der Änderung in eine Prüftabelle, bevor die Änderung durchgeführt wird. Mit dem INSTEAD OF-Trigger können Sie Daten aus den Ansichten einfügen, aktualisieren oder löschen, die auf Daten aus mehreren Tabellen verweisen, zusätzlich zu der Möglichkeit, einen Teil einer Stapelabfrage abzulehnen und einen anderen Teil dieses Stapels erfolgreich auszuführen. Der INSTEAD OF-Trigger kann nicht mit aktualisierbaren Ansichten mit WITH CHECK OPTION und in Tabellen mit einer referenziellen Beziehung verwendet werden, die Kaskadenaktionen bei DELETE oder UPDATE angibt.

Nachdem wir die Auslöser theoretisch besprochen haben, beginnen wir damit, zu zeigen, was wir praktisch besprechen. In den kommenden Demos werden wir die verschiedenen Situationen zeigen, in denen wir von den SQL Server-Triggern profitieren können.

NACH… DML-Trigger

Angenommen, wir müssen die DML-Aktionen verfolgen, die für eine bestimmte Tabelle ausgeführt werden, und diese Protokolle in eine Verlaufstabelle schreiben, in der die ID des eingefügten, aktualisierten oder gelöschten Datensatzes und die durchgeführte Aktion in die Verlaufstabelle geschrieben werden. Die folgenden CREATE TABLE T-SQL-Anweisungen können verwendet werden, um sowohl die Quell- als auch die Verlaufstabellen zu erstellen:

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

Um die INSERT-Operation zu verfolgen, erstellen wir einen DML-Trigger, der ausgelöst wird, nachdem eine INSERT-Operation für die übergeordnete Tabelle ausgeführt wurde. Dieser Trigger ruft den zuletzt eingefügten ID-Wert für diese übergeordnete Tabelle aus der virtuellen eingefügten Tabelle ab, wie in der CREATE TRIGGER T-SQL-Anweisung unten:

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

Die Nachverfolgung des DELETE-Vorgangs kann erreicht werden, indem ein DML-Trigger erstellt wird, der ausgelöst wird, nachdem der DELETE-Vorgang für die übergeordnete Tabelle ausgeführt wurde. Auch hier ruft der Trigger den ID-Wert des letzten gelöschten Datensatzes aus dieser übergeordneten Tabelle aus der virtuellen gelöschten Tabelle ab, wie in der CREATE TRIGGER T-SQL-Anweisung unten:

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

Schließlich verfolgen wir auch die UPDATE-Operation, indem wir einen DML-Trigger erstellen, der ausgelöst wird, nachdem eine UPDATE-Operation für die übergeordnete Tabelle ausgeführt wurde. Innerhalb dieses Triggers rufen wir den letzten aktualisierten ID-Wert aus dieser übergeordneten Tabelle aus der virtuell eingefügten Tabelle ab, wobei zu berücksichtigen ist, dass der UPDATE-Prozess durch Löschen des Datensatzes und Einfügen eines neuen Datensatzes mit den aktualisierten Werten wie im CREATE TRIGGER durchgeführt wird T-SQL-Anweisung unten:

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

Die Tabellen und die Trigger sind jetzt bereit für unsere Tests. Wenn Sie versuchen, mit der folgenden INSERT INTO T-SQL-Anweisung einen neuen Datensatz in die übergeordnete Tabelle einzufügen:

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

Wenn Sie dann den Ausführungsplan überprüfen, der durch Ausführen der vorherigen INSERT-Anweisung generiert wurde, werden Sie feststellen, dass zwei Einfügeoperationen ausgeführt werden, die sich auf zwei Tabellen auswirken. die übergeordnete Tabelle mit den in der INSERT-Anweisung angegebenen Werten und die Verlaufstabelle aufgrund des Auslösens des AFTER INSERT-Triggers, wie im folgenden Ausführungsplan gezeigt:

Es wird auch deutlich, wenn Sie die Daten überprüfen, die sowohl in die Eltern- als auch in die Verlaufstabellen eingefügt wurden, indem Sie die folgenden SELECT-Anweisungen verwenden:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Dabei werden die in der INSERT-Anweisung angegebenen Werte in die übergeordnete Tabelle eingefügt, und das Einfügungsprotokoll, das die ID des eingefügten Datensatzes und die durchgeführte Operation enthält, wird in die Verlaufstabelle eingefügt, wie im folgenden Ergebnis gezeigt:

Wenn Sie nun versuchen, einen vorhandenen Datensatz in der übergeordneten Tabelle mit der folgenden T-SQL-Anweisung UPDATE zu aktualisieren:

UPDATE TriggerDemo_Parent SET Emp_Salary=550 WHERE ID=1

Und überprüfen Sie den Ausführungsplan, der durch Ausführen der vorherigen UPDATE-Anweisung generiert wurde. Sie werden sehen, dass auf die Aktualisierungsoperation eine Einfügeoperation folgt, die zwei verschiedene Tabellen betrifft; Die übergeordnete Tabelle wird mit dem in der UPDATE-Anweisung und der Einfügeoperation in die Verlaufstabelle angegebenen Wert aktualisiert, da der AFTER UPDATE-Trigger ausgelöst wird, wie im folgenden Ausführungsplan gezeigt:

Überprüfen sowohl der übergeordneten als auch der Verlaufstabellendatensätze mit den folgenden SELECT-Anweisungen:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Sie werden sehen, dass die Update-Anweisung den Emp_Salary-Wert in der übergeordneten Tabelle mit dem in der UPDATE-Anweisung angegebenen Wert ändert, und das Aktualisierungsprotokoll, das die ID des aktualisierten Datensatzes und die durchgeführte Operation enthält, wird in die Verlaufstabelle eingefügt, als im Ergebnis unten gezeigt:

Im letzten Szenario des AFTER DML-Triggers verfolgen wir das Löschen eines vorhandenen Datensatzes aus der übergeordneten Tabelle mit der folgenden T-SQL-Anweisung DELETE:

DELETE FROM  TriggerDemo_Parent WHERE ID=1

Überprüfen Sie dann den Ausführungsplan, der durch Ausführen der vorherigen DELETE-Anweisung generiert wurde. Sie werden sehen, dass auf die DELETE-Operation die Einfügeoperation folgt, die sich auf zwei verschiedene Tabellen auswirkt. die übergeordnete Tabelle, aus der der Datensatz mit der bereitgestellten ID in der WHERE-Klausel der DELETE-Anweisung gelöscht wird, und die Einfügeoperation in die Verlaufstabelle aufgrund des Auslösens des AFTER DELETE-Triggers, wie im folgenden Ausführungsplan gezeigt:

Wenn Sie sowohl die Datensätze der Eltern- als auch der Verlaufstabelle mit den folgenden SELECT-Anweisungen überprüfen:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Sie werden sehen, dass der Datensatz mit dem ID-Wert gleich 1 aus der übergeordneten Tabelle gelöscht wurde, die in der DELETE-Anweisung bereitgestellt wird, und das Löschprotokoll, das die ID des gelöschten Datensatzes und die durchgeführte Operation enthält, wird in die Verlaufstabelle eingefügt , wie im Ergebnis unten gezeigt:

ANSTATT VON… DML-Trigger

Der zweite Typ von DML-Triggern ist der INSTEAD OF DML-Trigger. Wie bereits erwähnt, überschreibt der INSTEAD OF-Trigger die Anweisung der Aktion, die den Trigger auslöst, mit der im Trigger bereitgestellten Anweisung. Angenommen, wir müssen die DML-Aktionen protokollieren, die Benutzer für eine bestimmte Tabelle auszuführen versuchen, ohne ihnen die Ausführung dieser Aktion zu gestatten. Die folgenden CREATE TABLE T-SQL-Anweisungen können verwendet werden, um sowohl die Quell- als auch die alternativen Tabellen zu erstellen:

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

Nachdem wir die beiden Tabellen erstellt haben, fügen wir einen einzelnen Datensatz in die Quelltabelle für unsere Demo ein, indem wir die Anweisung INSERT INTO unten verwenden:

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

Für diese Demo erstellen wir drei Trigger, um die Operationen INSERT, UPDATE und DELETE zu überschreiben. Der erste Trigger wird verwendet, um zu verhindern, dass Einfügevorgänge in der übergeordneten Tabelle und im Protokoll in die alternative Tabelle geändert werden. Der Trigger wird mit der folgenden T-SQL-Anweisung CREATE TRIGGER erstellt:

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

Der zweite Trigger wird verwendet, um zu verhindern, dass Aktualisierungsvorgänge an der übergeordneten Tabelle und dem Protokoll in die alternative Tabelle geändert werden. Dieser Trigger wird wie folgt erstellt:

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

Der letzte Trigger wird verwendet, um zu verhindern, dass Löschvorgänge in der übergeordneten Tabelle und im Protokoll in die alternative Tabelle geändert werden. Dieser Trigger wird wie folgt erstellt:

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

Die zwei Tische und die drei Trigger sind jetzt fertig. Wenn Sie versuchen, mit der folgenden INSERT INTO T-SQL-Anweisung einen neuen Wert in die übergeordnete Tabelle einzufügen:

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

Überprüfen Sie dann sowohl die übergeordneten als auch die alternativen Tabellendatensätze mit den folgenden SELECT-Anweisungen:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Aufgrund der Tatsache, dass wir den INSTEAD OF INSERT-Trigger in der übergeordneten Tabelle haben, sehen Sie am Ergebnis, dass kein neuer Datensatz in die übergeordnete Tabelle eingefügt wird und ein Protokoll für die Einfügeoperation wie gezeigt in die alternative Tabelle eingefügt wird im Ergebnis unten:

Versuch, einen vorhandenen Datensatz in der übergeordneten Tabelle mit der folgenden T-SQL-Anweisung UPDATE zu aktualisieren:

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Überprüfen Sie dann sowohl die übergeordneten als auch die alternativen Tabellendatensätze mit den folgenden SELECT-Anweisungen:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Sie werden aus dem Ergebnis ersehen, dass der Wert Emp_Salary des Datensatzes mit dem ID-Wert gleich 1 aus der übergeordneten Tabelle nicht geändert wird und das Protokoll für den Aktualisierungsvorgang in die alternative Tabelle eingefügt wird, da der Auslöser INSTEAD OF UPDATE vorhanden ist in der übergeordneten Tabelle, wie im Ergebnis unten gezeigt:

Wenn wir schließlich versuchen, einen vorhandenen Datensatz aus der übergeordneten Tabelle mit der folgenden DELETE T-SQL-Anweisung zu löschen:

DELETE FROM  TriggerDemo_NewParent  WHERE ID=1

Und überprüfen Sie sowohl die übergeordneten als auch die alternativen Tabellendatensätze mit den folgenden SELECT-Anweisungen:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Aus dem Ergebnis geht hervor, dass der Datensatz mit dem ID-Wert gleich 1 aus der übergeordneten Tabelle nicht gelöscht wird und das Protokoll für die Löschoperation in die alternative Tabelle eingefügt wird, da der INSTEAD OF DELETE-Trigger in der übergeordneten Tabelle vorhanden ist Tabelle, wie im Ergebnis unten gezeigt:

NACH… DML-Trigger mit Nachrichten

Der AFTER-Trigger kann auch verwendet werden, um eine Warnmeldung für einen Benutzer auszulösen. In diesem Fall handelt es sich bei der Abfrage um eine Informationsnachricht, die die Ausführung der Anweisung, die diesen Trigger auslöst, nicht verhindert. Lassen Sie uns den zuvor erstellten INSTEAD OF UPDATE-Trigger löschen und durch einen anderen AFTER UPDATE-Trigger ersetzen, der einen Warnfehler auslöst, nachdem ein Aktualisierungsvorgang mit den folgenden DROP/CREATE TRIGGER-T-SQL-Anweisungen durchgeführt wurde:

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  

Wenn Sie versuchen, den Emp_Salary-Wert des Mitarbeiters mit dem ID-Wert gleich 1 zu aktualisieren, indem Sie die folgende UDPATE-Anweisung verwenden:

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

In den Meldungen wird eine Fehlermeldung ausgegeben Registerkarte, die die im erstellten Trigger bereitgestellte Nachricht enthält, wie unten gezeigt:

Überprüfen der Daten der übergeordneten Tabelle mit der folgenden SELECT-Anweisung:

SELECT * FROM TriggerDemo_NewParent

Sie werden am Ergebnis sehen, dass Emp_Salary erfolgreich aktualisiert wurde, wie unten gezeigt:

Wenn Sie den AFTER UPDATE-Trigger benötigen, um den Aktualisierungsvorgang nach dem Auslösen der Fehlermeldung zu stoppen, wird der ROLLBACK -Anweisung kann dem Trigger hinzugefügt werden, um die Aktualisierungsoperation, die diesen Trigger ausgelöst hat, rückgängig zu machen, wobei daran erinnert wird, dass der Trigger und die Anweisung, die den Trigger auslöst, in derselben Transaktion ausgeführt werden. Dies kann mit der T-SQL-Anweisung ALTER TRIGGER erreicht werden, siehe:

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

Wenn Sie versuchen, den Emp_Salary-Wert des Mitarbeiters mit der ID gleich 1 zu aktualisieren, indem Sie die UPDATE-Anweisung unten verwenden:

UPDATE TriggerDemo_NewParent SET Emp_Salary=700 WHERE ID=1

Auch hier wird eine Fehlermeldung in den Meldungen angezeigt aber dieses Mal wird der Aktualisierungsvorgang vollständig rückgängig gemacht, wie in den folgenden Fehlermeldungen gezeigt:

Überprüfen des Werts aus der Quelltabelle mit der folgenden SELECT-Anweisung:

SELECT * FROM TriggerDemo_NewParent

Sie werden sehen, dass sich der Emp_Salary-Wert nicht geändert hat, da der AFTER UPDATE-Trigger die gesamte Transaktion rückgängig gemacht hat, nachdem die Fehlermeldung ausgegeben wurde, wie im Tabellenergebnis unten gezeigt:

Trigger-Nachteile

Mit all den genannten Vorteilen der SQL Server-Trigger erhöhen die Trigger die Komplexität der Datenbank. Wenn der Trigger schlecht konzipiert oder überbeansprucht ist, führt dies zu erheblichen Leistungsproblemen, wie z. B. blockierten Sitzungen, da die Lebensdauer der Transaktion länger verlängert wird, zusätzlicher Overhead auf dem System, da er jedes Mal ausgeführt wird, wenn ein INSERT, UPDATE oder DELETE-Aktion wird ausgeführt oder es kann zu Datenverlustproblemen führen. Außerdem ist es nicht einfach, die Datenbank-Trigger anzuzeigen und zu verfolgen, insbesondere wenn es keine Dokumentation darüber gibt, da sie für Entwickler und die Anwendungen unsichtbar ist.

Alternativen auslösen … Integrität erzwingen

Wenn sich herausstellt, dass die Trigger die Leistung Ihrer SQL Server-Instanz beeinträchtigen, müssen Sie sie durch andere Lösungen ersetzen. Anstatt beispielsweise die Trigger zu verwenden, um die Entitätsintegrität zu erzwingen, sollte sie auf der niedrigsten Ebene erzwungen werden, indem die PRIMARY KEY- und UNIQUE-Einschränkungen verwendet werden. Dasselbe gilt für die Domänenintegrität, die durch CHECK-Einschränkungen erzwungen werden sollte, und die referenzielle Integrität, die durch die FOREIGN KEY-Einschränkungen erzwungen werden sollte. Sie können die DML-Trigger nur verwenden, wenn die von einer bestimmten Einschränkung unterstützten Funktionen Ihre Anwendungsanforderungen nicht erfüllen können.

Vergleichen wir die Erzwingung der Domänenintegrität mithilfe von DML-Triggern und der Verwendung der CHECK-Einschränkungen. Angenommen, wir müssen das Einfügen positiver Werte nur in die Spalte Emp_Salary erzwingen. Wir beginnen mit dem Erstellen einer einfachen Tabelle mit der folgenden T-SQL-Anweisung CREATE TABLE:

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

Definieren Sie dann den DML-Trigger AFTER INSERT, der sicherstellt, dass Sie einen positiven Wert in die Spalte Emp_Salary einfügen, indem Sie die Transaktion zurücksetzen, wenn ein Benutzer einen negativen Gehaltswert einfügt, indem Sie die CREATE TRIGGER T-SQL-Anweisung unten verwenden:

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

Zu Vergleichszwecken erstellen wir eine weitere einfache Tabelle mit demselben Schema und definieren eine CHECK-Einschränkung innerhalb der CREATE TABLE-Anweisung, um nur positive Werte in der Emp_Salary-Spalte zu akzeptieren, wie unten gezeigt:

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

Wenn Sie versuchen, den folgenden Datensatz, der einen negativen Emp_Salary-Wert enthält, in die erste Tabelle einzufügen, die einen vordefinierten Trigger hat, indem Sie die INSERT INTO-Anweisung unten verwenden:

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

Die INSERT-Anweisung schlägt fehl und gibt eine Fehlermeldung aus, die anzeigt, dass Sie keinen negativen Wert in die Emp_Salary-Spalte einfügen und die gesamte Transaktion aufgrund eines AFTER INSERT-Triggers zurücksetzen können, wie in der folgenden Fehlermeldung gezeigt:

Auch wenn Sie versuchen, denselben Datensatz, der einen negativen Emp_Salary-Wert enthält, in die zweite Tabelle einzufügen, die eine vordefinierte CHECK-Einschränkung hat, indem Sie die INSERT INTO-Anweisung unten verwenden:

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

Die INSERT-Anweisung schlägt erneut fehl und zeigt an, dass Sie versuchen, den Wert einzufügen, der mit der CHECK-Einschränkungsbedingung in Konflikt steht, wie in der folgenden Fehlermeldung gezeigt:

Aus den vorherigen Ergebnissen sehen Sie, dass sowohl die Trigger- als auch die CHECK-Einschränkungsmethoden das Ziel erreichen, indem Sie daran gehindert werden, negative Emp_Salary-Werte einzufügen. Aber welcher ist besser? Lassen Sie uns die Leistung der beiden Methoden vergleichen, indem wir die Gewichtung des Ausführungsplans für jede Methode überprüfen. Aus den generierten Ausführungsplänen nach Ausführung der beiden Abfragen sehen Sie, dass die Gewichtung der Triggermethode dreimal beträgt die Gewichtung der CHECK-Einschränkungsmethode, wie im Vergleich der Ausführungspläne unten gezeigt:

Um die von jedem einzelnen verbrauchte Ausführungszeit zu vergleichen, lassen Sie uns außerdem jeden 1000-mal mit den folgenden T-SQL-Anweisungen ausführen:

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

Sie werden sehen, dass die erste Methode, die den Trigger verwendet, ungefähr 31 ms dauert vollständig ausgeführt werden, wobei die zweite Methode, die die CHECK-Einschränkung verwendet, nur 17 ms benötigt , was etwa 0,5 der Zeit entspricht erforderlich in der Methode, die den Trigger verwendet. Dies liegt daran, dass der Trigger die Transaktionslebensdauer verlängert und die Abfrage zurücksetzt, die den Trigger auslöst, nachdem er ausgeführt wurde, wenn eine Integritätsverletzung festgestellt wird, was zu einer Leistungsverschlechterung aufgrund des Rollback-Prozesses führt. Anders verhält es sich bei der Verwendung der CHECK-Einschränkung, bei der die Einschränkung ihre Aufgabe erfüllt, bevor sie Änderungen an den Daten vornimmt, und im Falle einer Verletzung kein Rollback erfordert.

Trigger-Alternativen … Auditing

Wie bereits erwähnt, können die Trigger auch verwendet werden, um die an einer bestimmten Tabelle vorgenommenen Änderungen zu prüfen und zu verfolgen. Wenn diese Überwachungsmethode eine Leistungsminderung in Ihrer SQL Server-Instanz verursacht, können Sie sie einfach durch OUTPUT ersetzen Klausel. Die OUTPUT-Klausel gibt Informationen über jede Zeile zurück, die von der INSERT-, UPDATE- oder DELETE-Operation betroffen ist, in Form einer Bestätigungsnachricht oder eines Werts, der in die historische Tabelle eingefügt werden kann. Die Methode der OUTPUT-Klausel bietet uns auch mehr Kontrolle über den ausgeführten Code, da sie der Anweisung zum Einfügen, Ändern oder Löschen von Daten selbst hinzugefügt wird, wann immer Sie möchten, im Gegensatz zum Trigger, der immer ausgeführt wird.

Vergleichen wir die Protokollierung der Dateneinfügung und -änderung in die Verlaufstabelle mithilfe von DML-Triggern und der Verwendung der OUTPUT-Klausel. Wir beginnen mit der Erstellung der folgenden Produktions- und Verlaufstabellen mit der folgenden T-SQL-Anweisung CREATE TABLE:

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

Sobald beide Tabellen erfolgreich erstellt wurden, erstellen wir den DML-Trigger AFTER INSERT, UPDATE, der einen Datensatz in die Verlaufstabelle schreibt, wenn eine neue Zeile in die Produktionstabelle eingefügt oder ein vorhandener Datensatz mithilfe der T-SQL-Anweisung CREATE TRIGGER geändert wird unten:

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

Um die Protokollierung der Änderungen mit der Trigger-Methode und der OUTPUT-Klausel zu vergleichen, müssen wir zwei neue einfache Tabellen erstellen, die Produktions- und die Verlaufstabelle, mit demselben Schema wie die beiden vorherigen Tabellen, aber diesmal ohne einen Trigger zu definieren, indem wir die verwenden CREATE TABLE T-SQL-Anweisungen unten:

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

Jetzt sind die vier Tische bereit für den Test. Wir fügen einen Datensatz in die erste Produktionstabelle ein, die einen Trigger hat, indem wir die Anweisung INSERT INTO T-SQL unten verwenden:

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

Dann fügen wir denselben Datensatz mit der OUTPUT-Klausel in die zweite Produktionstabelle ein. Die folgende INSERT INTO-Anweisung fungiert als zwei Einfügeanweisungen; die erste fügt denselben Datensatz in die Produktionstabelle ein und die zweite Einfügeanweisung neben der OUTPUT-Klausel fügt das Einfügungsprotokoll in die Verlaufstabelle ein:

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

Wenn Sie die in die vier Produktions- und Verlaufstabellen eingefügten Daten überprüfen, werden Sie feststellen, dass beide Methoden, die Trigger- und die OUTPUT-Methode, dasselbe Protokoll erfolgreich und auf die gleiche Weise in die Verlaufstabelle schreiben, wie im folgenden Ergebnis gezeigt:

Aus den generierten Ausführungsplänen nach Ausführung der beiden Abfragen sehen Sie, dass die Gewichtung der Triggermethode bei etwa (21 % + 36 %) 57 % liegt des Gesamtgewichts, wobei das Gewicht der OUTPUT-Methode etwa 43 % beträgt , mit einem kleinen Gewichtsunterschied, wie im Vergleich der Ausführungspläne unten gezeigt:

Der Leistungsunterschied wird deutlich, wenn man die von jeder Methode verbrauchte Ausführungszeit vergleicht, wobei das Protokollieren der Änderungen mit der Triggermethode (114+125) 239 ms verbraucht vollständig ausgeführt werden, und die Methode, die die Methode der OUTPUT-Klausel verwendet, verbraucht nur 5 ms , also 2 % der in der Triggermethode verwendeten Zeit, wie deutlich aus der Zeitstatistik unten hervorgeht:

Aus dem vorherigen Ergebnis geht nun klar hervor, dass die Verwendung der OUTPUT-Methode besser ist als die Verwendung von Triggern für die Änderungsprüfung.

Nützliche Links:

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