sql >> Database >  >> RDS >> Sqlserver

SQL Server-trigger:inzicht en alternatieven

De SQL Server-trigger is een speciaal type opgeslagen procedures dat automatisch wordt uitgevoerd wanneer zich een gebeurtenis voordoet op een specifieke databaseserver. SQL Server biedt ons twee hoofdtypen triggers:de DML Triggers en de DDL triggers. De DDL-triggers worden geactiveerd als reactie op verschillende DDL-gebeurtenissen (Data Definition Language), zoals het uitvoeren van CREATE-, ALTER-, DROP-, GRANT-, DENY- en REVOKE T-SQL-instructies. De DDL-trigger kan reageren op de DDL-acties door te voorkomen dat deze wijzigingen de database beïnvloeden, een andere actie uitvoeren als reactie op deze DDL-acties of deze wijzigingen opnemen die worden uitgevoerd op de database.

De SQL Server DML-trigger is een speciaal type opgeslagen procedures dat is ontworpen om een ​​reeks acties uit te voeren op een databasetabel, waaraan de trigger is gekoppeld, wanneer een Data Manipulation Language (DML)-gebeurtenis, zoals INSERT, UPDATE of DELETE actie, vindt plaats om de inhoud van de databasetabellen of -views te wijzigen, ongeacht of de tabelrijen worden beïnvloed of niet. De triggers verschillen van de opgeslagen procedures doordat de triggers automatisch worden geactiveerd wanneer een vooraf gedefinieerde gegevenswijziging plaatsvindt. De DML-triggers kunnen worden gebruikt om de gegevensintegriteit te behouden en bedrijfsregels af te dwingen, net als de functionaliteit voor tabelcontrole en externe sleutels, door auditprocessen en andere post-DML-acties uit te voeren. U kunt de DML-triggers gebruiken om andere tabellen te doorzoeken en complexe T-SQL-query's uit te voeren.

Als de trigger wordt geactiveerd, wordt een speciaal type virtuele tafels genaamd Ingevoegd en Verwijderd tabellen worden gebruikt om de gegevenswaarden voor en na de wijziging te behouden. De trigger-instructie werkt binnen het bereik van dezelfde transactie die die trigger activeert. Dit betekent dat de transactie pas volledig wordt doorgevoerd nadat de trigger-instructie met succes is voltooid. Aan de andere kant wordt de transactie teruggedraaid als de trigger-instructie mislukt.

Er zijn twee soorten DML-triggers:NA of VOOR trigger en IN PLAATS VAN trekker. De AFTER-trigger wordt geactiveerd en uitgevoerd na het uitvoeren van de INSERT-, UPDATE- of DELETE-actie die deze met succes heeft geactiveerd. Ook moeten alle referentiële cascade-acties en beperkingscontroles slagen voordat de trigger wordt geactiveerd. De AFTER-trigger kan alleen op tabelniveau worden gedefinieerd zonder de mogelijkheid om deze in weergaven te definiëren. De INSTEAD OF-trigger wordt gebruikt om de instructie van de actie die de trigger activeert te overschrijven met de instructie in de trigger, en die instructie terug te draaien nadat er een fout is opgetreden wanneer iemand een actie probeert uit te voeren die een specifiek beleid schendt, zoals bijwerken een kritische financiële kolom of het schrijven van de wijziging in een controletabel voordat de wijziging wordt uitgevoerd. Met de INSTEAD OF-trigger kunt u gegevens INVOEGEN, BIJWERKEN of VERWIJDEREN uit de views die verwijzen naar gegevens uit meerdere tabellen, naast de mogelijkheid om een ​​deel van een batchquery te weigeren en een ander deel van die batch met succes uit te voeren. De trigger INSTEAD OF kan niet worden gebruikt met de bijwerkbare weergaven die WITH CHECK OPTION hebben en in de tabellen met een referentiële relatie die trapsgewijze acties specificeert op DELETE of UPDATE.

Nadat we de triggers theoretisch hebben besproken, gaan we laten zien wat we praktisch bespreken. In de komende demo's laten we de verschillende situaties zien waarin we voordeel kunnen halen uit de SQL Server-triggers.

NA... DML-trigger

Stel dat we de DML-acties moeten volgen die op een specifieke tabel zijn uitgevoerd en deze logs in een geschiedenistabel moeten schrijven, waar de ID van het ingevoegde, bijgewerkte of verwijderde record en de uitgevoerde actie naar de geschiedenistabel zullen worden geschreven. De onderstaande CREATE TABLE T-SQL-instructies kunnen worden gebruikt om zowel de bron- als de geschiedenistabellen te maken:

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

Om de INSERT-bewerking te volgen, maken we een DML-trigger die wordt geactiveerd na het uitvoeren van een INSERT-bewerking op de bovenliggende tabel. Deze trigger haalt de laatst ingevoegde ID-waarde van die bovenliggende tabel op uit de virtueel ingevoegde tabel, zoals in de onderstaande CREATE TRIGGER T-SQL-instructie:

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

Het volgen van de DELETE-bewerking kan worden bereikt door een DML-trigger te maken die wordt geactiveerd na het uitvoeren van de DELETE-bewerking op de bovenliggende tabel. Nogmaals, de trigger haalt de ID-waarde op van het laatst verwijderde record van die bovenliggende tabel uit de virtueel verwijderde tabel, zoals in de CREATE TRIGGER T-SQL-instructie hieronder:

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

Ten slotte zullen we ook de UPDATE-bewerking volgen door een DML-trigger te maken die wordt geactiveerd na het uitvoeren van een UPDATE-bewerking op de bovenliggende tabel. Binnen deze trigger halen we de laatst bijgewerkte ID-waarde van die bovenliggende tabel op uit de virtueel ingevoegde tabel, rekening houdend met het feit dat het UPDATE-proces wordt uitgevoerd door de record te verwijderen en een nieuwe record in te voegen met de bijgewerkte waarden, zoals in de CREATE TRIGGER T-SQL-verklaring hieronder:

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

De tabellen en de triggers zijn nu klaar voor onze testen. Als u een nieuw record in de bovenliggende tabel probeert in te voegen met behulp van de onderstaande instructie INSERT INTO T-SQL:

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

Als u vervolgens het uitvoeringsplan controleert dat is gegenereerd door het vorige INSERT-statement uit te voeren, ziet u dat er twee invoegbewerkingen worden uitgevoerd, die van invloed zijn op twee tabellen; de bovenliggende tabel met de waarden gespecificeerd in de INSERT-instructie en de geschiedenistabel vanwege het activeren van de AFTER INSERT-trigger, zoals weergegeven in het onderstaande uitvoeringsplan:

Het is ook duidelijk wanneer u de gegevens controleert die zijn ingevoegd in zowel de ouder- als de geschiedenistabellen met behulp van de onderstaande SELECT-instructies:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

Waar de waarden gespecificeerd in de INSERT-instructie worden ingevoegd in de bovenliggende tabel, en het invoeglogboek dat de ID van het ingevoegde record en de uitgevoerde bewerking bevat, wordt ingevoegd in de geschiedenistabel, zoals weergegeven in het onderstaande resultaat:

Als u nu een bestaand record in de bovenliggende tabel probeert bij te werken met behulp van de onderstaande UPDATE T-SQL-instructie:

UPDATE TriggerDemo_Parent SET Emp_Salary=550 WHERE ID=1

En controleer het uitvoeringsplan dat is gegenereerd door de vorige UPDATE-instructie uit te voeren, u zult zien dat de update-bewerking wordt gevolgd door een invoegbewerking die twee verschillende tabellen beïnvloedt; de bovenliggende tabel wordt bijgewerkt met de waarde die is opgegeven in de UPDATE-instructie en de invoegbewerking in de geschiedenistabel vanwege het activeren van de AFTER UPDATE-trigger, zoals weergegeven in het onderstaande uitvoeringsplan:

Het controleren van zowel de bovenliggende als de geschiedenistabelrecords met behulp van de onderstaande SELECT-instructies:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

U zult zien dat de update-instructie de waarde Emp_Salary in de bovenliggende tabel wijzigt met de waarde die is opgegeven in de UPDATE-instructie, en het updatelogboek dat de ID van het bijgewerkte record en de uitgevoerde bewerking bevat, wordt ingevoegd in de geschiedenistabel, zoals weergegeven in het onderstaande resultaat:

In het laatste scenario van de AFTER DML-trigger volgen we de verwijdering van een bestaand record uit de bovenliggende tabel met behulp van de onderstaande DELETE T-SQL-instructie:

DELETE FROM  TriggerDemo_Parent WHERE ID=1

Controleer vervolgens het uitvoeringsplan dat is gegenereerd door de vorige DELETE-instructie uit te voeren. U zult zien dat de DELETE-bewerking wordt gevolgd door de invoegbewerking, die van invloed is op twee verschillende tabellen; de bovenliggende tabel waaruit het record met de opgegeven ID in de WHERE-clausule van de DELETE-instructie wordt verwijderd en de invoegbewerking in de geschiedenistabel vanwege het activeren van de AFTER DELETE-trigger, zoals weergegeven in het onderstaande uitvoeringsplan:

Als u zowel de bovenliggende als de geschiedenistabelrecords controleert met behulp van de onderstaande SELECT-instructies:

SELECT * FROM TriggerDemo_Parent
GO
SELECT * FROM TriggerDemo_History

U zult zien dat het record met de ID-waarde gelijk aan 1 is verwijderd uit de bovenliggende tabel die is opgegeven in de DELETE-instructie, en het verwijderlogboek dat de ID van het verwijderde record en de uitgevoerde bewerking bevat, wordt ingevoegd in de geschiedenistabel , zoals weergegeven in het onderstaande resultaat:

IN PLAATS VAN... DML-trigger

Het tweede type DML-triggers is de INSTEAD OF DML-trigger. Zoals eerder vermeld, overschrijft de INSTEAD OF-trigger de instructie van de actie die de trigger activeert met de instructie in de trigger. Stel dat we de DML-acties moeten loggen die gebruikers proberen uit te voeren op een specifieke tabel, zonder dat ze die actie mogen uitvoeren. De onderstaande CREATE TABLE T-SQL-instructies kunnen worden gebruikt om zowel de bron- als alternatieve tabellen te maken:

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

Nadat we de twee tabellen hebben gemaakt, zullen we een enkele record invoegen in de brontabel voor onze demo met behulp van de onderstaande instructie INSERT INTO:

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

Voor deze demo zullen we drie triggers maken om de INSERT-, UPDATE- en DELETE-bewerkingen te negeren. De eerste trigger wordt gebruikt om te voorkomen dat invoegbewerkingen op de bovenliggende tabel en het logboek worden gewijzigd in de alternatieve tabel. De trigger wordt gemaakt met behulp van de onderstaande CREATE TRIGGER T-SQL-instructie:

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

De tweede trigger wordt gebruikt om te voorkomen dat een updatebewerking op de bovenliggende tabel en het logboek wordt gewijzigd in de alternatieve tabel. Deze trigger wordt als volgt gemaakt:

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

De laatste trigger wordt gebruikt om te voorkomen dat een verwijderbewerking op de bovenliggende tabel en het logboek verandert in de alternatieve tabel. Deze trigger wordt als volgt gemaakt:

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

De twee tafels en de drie triggers zijn nu klaar. Als u een nieuwe waarde in de bovenliggende tabel probeert in te voegen met behulp van de onderstaande instructie INSERT INTO T-SQL:

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

Controleer vervolgens zowel de bovenliggende als de alternatieve tabelrecords met behulp van de onderstaande SELECT-instructies:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Vanwege het feit dat we de INSTEAD OF INSERT-trigger in de bovenliggende tabel hebben, zult u aan het resultaat zien dat er geen nieuw record in de bovenliggende tabel wordt ingevoegd en dat er een logboek voor de invoegbewerking wordt ingevoegd in de alternatieve tabel, zoals weergegeven in het resultaat hieronder:

Proberen een bestaande record in de bovenliggende tabel bij te werken met behulp van de UPDATE T-SQL-instructie hieronder:

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Controleer vervolgens zowel de bovenliggende als de alternatieve tabelrecords met behulp van de onderstaande SELECT-instructies:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

U zult aan het resultaat zien dat de Emp_Salary-waarde van het record met de ID-waarde gelijk aan 1 uit de bovenliggende tabel niet wordt gewijzigd en dat het logboek voor de updatebewerking wordt ingevoegd in de alternatieve tabel vanwege de INSTEAD OF UPDATE-trigger in de bovenliggende tabel, zoals weergegeven in het onderstaande resultaat:

Als we ten slotte proberen een bestaand record uit de bovenliggende tabel te verwijderen met behulp van de onderstaande DELETE T-SQL-instructie:

DELETE FROM  TriggerDemo_NewParent  WHERE ID=1

En controleer zowel de bovenliggende als de alternatieve tabelrecords met behulp van de onderstaande SELECT-instructies:

SELECT * FROM TriggerDemo_NewParent
GO
SELECT * FROM TriggerDemo_InsteadParent

Het resultaat zal duidelijk zijn dat het record met de ID-waarde gelijk aan 1 uit de bovenliggende tabel niet zal worden verwijderd, en het logboek voor de verwijderbewerking wordt ingevoegd in de alternatieve tabel vanwege de INSTEAD OF DELETE-trigger in de bovenliggende tabel tabel, zoals weergegeven in het onderstaande resultaat:

NA... DML-trigger met berichten

De AFTER-trigger kan ook worden gebruikt om een ​​waarschuwingsbericht voor een gebruiker te genereren. In dit geval zal de query een informatief bericht zijn dat niet verhindert dat de instructie wordt uitgevoerd die die trigger activeert. Laten we de eerder gemaakte INSTEAD OF UPDATE-trigger laten vallen en deze vervangen door een andere AFTER UPDATE-trigger die een waarschuwingsfout genereert na het uitvoeren van een updatebewerking met behulp van de onderstaande DROP/CREATE TRIGGER T-SQL-instructies:

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  

Als u de Emp_Salary-waarde van de werknemer probeert bij te werken met de ID-waarde gelijk aan 1 met behulp van de onderstaande UDPATE-verklaring:

UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1

Er wordt een foutmelding weergegeven in de Berichten tabblad, dat het bericht bevat dat is opgegeven in de gemaakte trigger, zoals hieronder weergegeven:

De gegevens van de bovenliggende tabel controleren met behulp van de onderstaande SELECT-instructie:

SELECT * FROM TriggerDemo_NewParent

U zult aan het resultaat zien dat het Emp_Salary met succes is bijgewerkt, zoals hieronder weergegeven:

Als u de AFTER UPDATE-trigger nodig hebt om de update-bewerking te stoppen nadat de foutmelding is gegenereerd, wordt de ROLLBACK statement kan aan de trigger worden toegevoegd om de update-bewerking die die trigger heeft geactiveerd terug te draaien, waarbij wordt herinnerd aan het feit dat de trigger en de instructie die de trigger activeert, in dezelfde transactie worden uitgevoerd. Dit kan worden bereikt met behulp van het ALTER TRIGGER T-SQL-statement, zie:

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

Als u de Emp_Salary-waarde van de werknemer probeert bij te werken met de ID gelijk aan 1 met behulp van de onderstaande UPDATE-verklaring:

UPDATE TriggerDemo_NewParent SET Emp_Salary=700 WHERE ID=1

Nogmaals, er wordt een foutmelding weergegeven in de Berichten tabblad, maar deze keer wordt de update-bewerking volledig teruggedraaid, zoals weergegeven in de onderstaande foutmeldingen:

De waarde uit de brontabel controleren met behulp van de onderstaande SELECT-instructie:

SELECT * FROM TriggerDemo_NewParent

U zult zien dat de Emp_Salary-waarde niet is gewijzigd, aangezien de NA UPDATE-trigger de algehele transactie terugdraaide nadat de foutmelding was gegenereerd, zoals weergegeven in het onderstaande tabelresultaat:

Triggernadelen

Met alle genoemde voordelen van de SQL Server-triggers, verhogen de triggers de complexiteit van de database. Als de trigger slecht is ontworpen of te veel wordt gebruikt, zal dit leiden tot grote prestatieproblemen, zoals geblokkeerde sessies, vanwege het verlengen van de levensduur van de transactie, extra overhead op het systeem omdat het elke keer wordt uitgevoerd als een INSERT, UPDATE of DELETE-actie wordt uitgevoerd of dit kan leiden tot problemen met gegevensverlies. Het is ook niet eenvoudig om de database-triggers te bekijken en te traceren, vooral als er geen documentatie over is, omdat het onzichtbaar is voor ontwikkelaars en de applicaties.

Alternatieven activeren … Integriteit afdwingen

Als wordt vastgesteld dat de triggers de prestaties van uw SQL Server-instantie schaden, moet u ze vervangen door andere oplossingen. In plaats van de triggers te gebruiken om de integriteit van de entiteit af te dwingen, moet deze bijvoorbeeld op het laagste niveau worden afgedwongen met behulp van de PRIMARY KEY en UNIQUE-beperkingen. Hetzelfde geldt voor de domeinintegriteit die moet worden afgedwongen via CHECK-beperkingen, en de referentiële integriteit die moet worden afgedwongen via de FOREIGN KEY-beperkingen. U kunt de DML-triggers alleen gebruiken als de functies die door een specifieke beperking worden ondersteund, niet aan uw toepassingsvereisten kunnen voldoen.

Laten we een vergelijking maken tussen het afdwingen van de domeinintegriteit met behulp van DML-triggers en het gebruik van de CHECK-beperkingen. Stel dat we het invoegen van positieve waarden alleen in de kolom Emp_Salary moeten afdwingen. We beginnen met het maken van een eenvoudige tabel met behulp van het onderstaande CREATE TABLE T-SQL-statement:

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

Definieer vervolgens de AFTER INSERT DML-trigger die ervoor zorgt dat u een positieve waarde invoegt in de kolom Emp_Salary door de transactie terug te draaien als een gebruiker een negatieve salariswaarde invoegt, met behulp van de CREATE TRIGGER T-SQL-verklaring hieronder:

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

Voor vergelijkingsdoeleinden zullen we een andere eenvoudige tabel maken, met hetzelfde schema, en een CHECK-beperking definiëren binnen de CREATE TABLE-instructie om alleen positieve waarden in de Emp_Salary-kolom te accepteren, zoals hieronder weergegeven:

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

Als u de onderstaande record probeert in te voegen die een negatieve Emp_Salary-waarde bevat in de eerste tabel met een vooraf gedefinieerde trigger, met behulp van de onderstaande instructie INSERT INTO:

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

De INSERT-instructie zal geen foutmelding geven die aangeeft dat u geen negatieve waarde in de Emp_Salary-kolom kunt invoegen en de algehele transactie niet kunt terugdraaien vanwege een AFTER INSERT-trigger, zoals weergegeven in de onderstaande foutmelding:

Als u hetzelfde record probeert in te voegen dat een negatieve Emp_Salary-waarde bevat in de tweede tabel die een vooraf gedefinieerde CHECK-beperking heeft, met behulp van de onderstaande instructie INSERT INTO:

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

De INSERT-instructie zal opnieuw mislukken om aan te tonen dat u de waarde probeert in te voegen die in strijd is met de CHECK-beperkingsvoorwaarde, zoals weergegeven in het onderstaande foutbericht:

Uit de vorige resultaten ziet u dat zowel de trigger- als de CHECK-beperkingsmethode het doel bereiken door te voorkomen dat u negatieve Emp_Salary-waarden invoegt. Maar welke is beter? Laten we de prestaties van de twee methoden vergelijken door het gewicht van het uitvoeringsplan voor elke methode te controleren. Uit de gegenereerde uitvoeringsplannen na het uitvoeren van de twee query's, zult u zien dat het gewicht van de triggermethode drie keer is het gewicht van de controlebeperkingsmethode, zoals weergegeven in de onderstaande vergelijking van het uitvoeringsplan:

Om de uitvoeringstijd te vergelijken die door elk wordt verbruikt, laten we ze ook 1000 keer uitvoeren met behulp van de onderstaande T-SQL-instructies:

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

U zult zien dat de eerste methode die de trigger gebruikt ongeveer 31 ms . duurt volledig uit te voeren, waarbij de tweede methode die de CHECK-beperking gebruikt slechts 17ms duurt , wat ongeveer 0,5 keer is vereist in de methode die de trigger gebruikt. Dit komt door het feit dat de trigger de transactielevensduur verlengt en de query die de trigger activeert terugdraait nadat deze is uitgevoerd wanneer een integriteitsschending wordt gevonden, waardoor de prestaties afnemen als gevolg van het terugdraaiproces. Het geval is anders bij het gebruik van de CHECK-beperking, waarbij de beperking zijn werk zal doen voordat er enige wijziging in de gegevens wordt aangebracht, en er in geval van overtreding geen rollback nodig is.

Triggeralternatieven … Auditing

Zoals we eerder vermeldden, kunnen de triggers ook worden gebruikt om de wijzigingen die op een specifieke tabel zijn uitgevoerd, te controleren en bij te houden. Als deze controlemethode een prestatievermindering in uw SQL Server-instantie veroorzaakt, kunt u deze eenvoudig vervangen door de OUTPUT clausule. De OUTPUT-component retourneert informatie over elke rij die wordt beïnvloed door de INSERT-, UPDATE- of DELETE-bewerking, in de vorm van een bevestigingsbericht of een waarde die in de historische tabel kan worden ingevoegd. De OUTPUT-clausulemethode geeft ons ook meer controle over de uitgevoerde code, omdat deze wordt toegevoegd aan de instructie voor het invoegen, wijzigen of verwijderen van gegevens zelf wanneer u maar wilt, in tegenstelling tot de trigger die altijd wordt uitgevoerd.

Laten we een vergelijking maken tussen het loggen van het invoegen en wijzigen van gegevens in de geschiedenistabel met behulp van DML-triggers en het gebruik van de OUTPUT-clausule. We beginnen met het maken van de onderstaande productie- en geschiedenistabellen met behulp van de onderstaande CREATE TABLE T-SQL-instructie:

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

Zodra beide tabellen met succes zijn gemaakt, zullen we de AFTER INSERT, UPDATE DML-trigger maken die een record in de geschiedenistabel zal schrijven als een nieuwe rij in de productietabel wordt ingevoegd of een bestaand record wordt gewijzigd met behulp van de CREATE TRIGGER T-SQL-instructie hieronder:

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

Om het loggen van de wijzigingen met behulp van de triggermethode en de OUTPUT-component te vergelijken, moeten we twee nieuwe eenvoudige tabellen maken, de productie- en de geschiedenistabellen, met hetzelfde schema als de vorige twee tabellen, maar deze keer zonder een trigger te definiëren, met behulp van de MAAK TABEL T-SQL-statements hieronder:

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

Nu zijn de vier tafels klaar voor het testen. We zullen één record invoegen in de eerste productietabel die een trigger heeft met behulp van de onderstaande instructie INSERT INTO T-SQL:

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

Vervolgens zullen we hetzelfde record invoegen in de tweede productietabel met behulp van de OUTPUT-clausule. De onderstaande INSERT INTO-instructie werkt als twee insert-instructies; de eerste voegt hetzelfde record in de productietabel in en de tweede insert-instructie naast de OUTPUT-clausule voegt het invoeglogboek in de geschiedenistabel in:

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

Als u de gegevens controleert die zijn ingevoegd in de vier productie- en geschiedenistabellen, zult u zien dat beide methoden, de trigger- en OUTPUT-methoden, hetzelfde log met succes en op dezelfde manier in de geschiedenistabel zullen schrijven, zoals weergegeven in het onderstaande resultaat:

Uit de gegenereerde uitvoeringsplannen na het uitvoeren van de twee query's, zult u zien dat het gewicht van de triggermethode ongeveer (21%+36%) is 57% van het totale gewicht, waarbij het gewicht van de OUTPUT-methode ongeveer 43% . is , met een klein gewichtsverschil, zoals te zien is in de onderstaande vergelijking van de uitvoeringsplannen:

Het prestatieverschil is duidelijk bij het vergelijken van de uitvoeringstijd die door elke methode wordt verbruikt, waarbij het loggen van de wijzigingen met behulp van de triggermethode (114+125) 239ms kost. volledig moet worden uitgevoerd, en de methode die de OUTPUT-clausulemethode gebruikt, verbruikt slechts 5ms , wat 2% . is van de tijd die wordt gebruikt in de triggermethode, zoals duidelijk blijkt uit de onderstaande tijdstatistieken:

Het is nu duidelijk uit het vorige resultaat dat het gebruik van de OUTPUT-methode beter is dan het gebruik van triggers voor het controleren van wijzigingen.

Nuttige links:

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

  1. Hoe maak je een PL/SQL-functie in Oracle Database?

  2. SQL Server PIVOT misschien?

  3. Hoe het huidige Connection-object in Spring JDBC te krijgen

  4. MySQL NDB-cluster implementeren en beheren met ClusterControl