SQL Server: Deaktivieren des Auslösers für ein Update nur für Ihre aktuelle Sitzung


15

Ich arbeite an SQL Server 2008 R2.

Ich habe eine Tabelle Vorteil , die eine AFTER INSERT, UPDATE - Trigger genannt hat tiu_benefit .

Ich möchte eine UPDATE-Anweisung für diese Tabelle schreiben, um 1 Zeile zu aktualisieren, aber ich möchte nicht, dass der Trigger ausgelöst wird. Ich weiß, dass ich den Trigger vor UPDATE deaktivieren und anschließend nach UPDATE aktivieren kann:

DISABLE TRIGGER tiu_benefit ON benefit;  
GO  
UPDATE benefit SET editor = 'srh' where benefit_id = 9876
GO
ENABLE TRIGGER tiu_benefit ON benefit;  
GO  

Dieser Auslöser zum Deaktivieren und Aktivieren wirkt sich jedoch auf alle derzeit angemeldeten Benutzer aus. Es besteht also die Möglichkeit, dass ein anderer Benutzer ein UPDATE / INSERT ausführt, während der Trigger von meinem Skript deaktiviert wird, was nicht gut ist. Deshalb möchte ich nur den Trigger für meine aktuelle Sitzung deaktivieren und aktivieren. Ist es möglich? Wenn ja, bitte erläutern Sie wie.

Vielen Dank


1
Wenn Sie Ihren Auslöser nicht ändern können, lautet die Antwort nein.
Jyao

Antworten:


6

Ich habe einige Tests durchgeführt, und ich denke, es wäre in Ordnung, wenn Sie Ihren Prozess in einer einzigen Transaktion ausführen.

BEGIN TRANSACTION
GO

DISABLE TRIGGER tiu_benefit ON benefit;
GO

UPDATE benefit
SET editor = 'srh'
WHERE benefit_id = 9876
GO

ENABLE TRIGGER tiu_benefit ON benefit;
GO

--Decide to commit or rollback

--commit
--rollback 

In meinen Tests habe ich nur das BEGIN TRANSACTIONund das DISABLE TRIGGERerste hervorgehoben und ausgeführt . Ich habe dann ein neues (zweiten) Abfrage - Fenster geöffnet und versuchte , verschiedene DML - Anweisungen (laufen SELECT, INSERT, UPDATE DELETE) gegen die Basistabelle. Alle Versuche, im zweiten Abfragefenster auf die Basistabelle zuzugreifen, haben auf die Sperren gewartet, die das Fenster mit der expliziten Transaktion hält. Nachdem ich meine explizite Transaktion festgeschrieben (oder zurückgesetzt) ​​hatte, konnte das zweite Fenster auf die Tabelle zugreifen.


Dies funktioniert, aber die Sperren können in Abhängigkeit davon, wie lange Sie die Transaktion geöffnet lassen, unbeabsichtigte Probleme verursachen.
CaM

@CaM - Ich würde davon ausgehen, dass ein einzeiliges Update nicht zu lange dauern würde, wenn das OP die Transaktion schnell festschreibt oder zurücksetzt. Hoffentlich gibt es einen Index über benefit_id:)
Scott Hodgin

Ich mochte diese Lösung wirklich, da ich keine Änderungen am Auslöser
vornehmen muss

18

Um Ihr Problem zu lösen, müssen wir programmatisch vorgehen. Es gibt zwei Routen, die Sie hier gehen können. Der Grund für die Notwendigkeit dieser Ansätze besteht darin, dass Sie einen Trigger für eine bestimmte Anweisung nicht deaktivieren können. Er kann nur für die gesamte Tabelle deaktiviert werden.

Option 1: Context_Info ()

Samuel Vanga bei MS SQL Tips hatte ein großartiges Beispiel:

USE AdventureWorks; 
GO 
-- creating the table in AdventureWorks database 
IF OBJECT_ID('dbo.Table1') IS NOT NULL 
DROP TABLE dbo.Table1 
GO 
CREATE TABLE dbo.Table1(ID INT) 
GO 
-- Creating a trigger 
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE 
AS 
DECLARE @Cinfo VARBINARY(128) 
SELECT @Cinfo = Context_Info() 
IF @Cinfo = 0x55555 
RETURN 
PRINT 'Trigger Executed' 
-- Actual code goes here 
-- For simplicity, I did not include any code 
GO

Wenn Samuel nicht möchte, dass der Trigger ausgeführt wird, verwenden sie Folgendes:

SET Context_Info 0x55555 
INSERT dbo.Table1 VALUES(100)

Context_Info verwendet die folgenden Systemansichten, um Informationen zur aktuellen Sitzung abzurufen:

  • sys.dm_exec_requests

  • sys.dm_exec_sessions

  • sys.sysprocesses

Die Ideologie hier ist, dass die von Ihnen festgelegte Binärzeichenfolge nur für die aktuelle Sitzung verfügbar ist. Wenn der Trigger also während Ihrer Sitzung ausgeführt wird, wird der Gültigkeitsbereich und die variable Einstellung der Context_infoFunktion angezeigt und es wird zum Escape-Teil des Triggers gesprungen stattdessen.

Option 2: Temp-Tabelle

Itzik Ben-Gan hat eine großartige Lösung in seinem Buch "Innerhalb von Microsoft SQL Server 2008 T-SQL-Programmierung: T-SQL-Programmierung", das sich auch in seinem späteren Buch T-SQL-Abfragen befindet . Das Hauptproblem bei dieser context_infoFunktion ist der geringe TempDB-Overhead.

Um die Überraschung zu verderben, aber die Handlung der Bücher nicht zu ruinieren (ich hatte das Gefühl, dass es sich lohnt, sie zu kaufen und zu lesen), werden Sie Ihren Auslöser ändern.

Ihr Trigger sollte eine Prüfung für eine temporäre Tabelle durchführen. Wenn die temporäre Tabelle vorhanden ist, sollte der Trigger wissen, dass er die Aktionen beendet und nicht ausführt.

Erstellen Sie in der Update-Anweisung, die Sie ausführen möchten, zuerst die temporäre Tabelle. Es wird in derselben Transaktion wie der Trigger angezeigt und bewirkt, dass der Trigger Ihre Anweisung ignoriert.

Beispiel eines Triggers:

CREATE TRIGGER TRIGGERNAME ON TABLENAME for INSERT AS

IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
GO

Beispiel für eine beginnende Anweisung, wenn der Trigger nicht ausgeführt werden soll:

CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);

Putting es insgesamt für Ihr Beispiel:

ALTER TRIGGER tiu_benefit ON benefit FOR 
... 
AS
...
IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
--... rest of code here
GO

CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);
UPDATE benefit SET editor = 'srh' where benefit_id = 9876;
GO

2
Ich würde context_info () anstelle der temporären Tabelle im Trigger verwenden. Mit anderen Worten, wenn ein Trigger feststellt, dass context_info einen bestimmten Wert zurückgibt, funktioniert der Trigger entsprechend. Sie können die relevante SO-Frage hier beziehen: stackoverflow.com/questions/3025662/…
Jyao

1
Sie können auch eine Prüfung durchführen, context_infomit original_login()der Sie festlegen, dass der Auslöser niemals ausgeführt werden soll, wenn eine bestimmte Person den Auslöser betätigt.
Kenneth Fisher

2

Ich würde entweder das CONTEXT_INFOoder das neuere verwenden SESSION_CONTEXT. Beide sind sitzungsbasierte Werte.

Eine Sache, die bezüglich der lokalen temporären Tabellenoption und sogar der Option zum Deaktivieren / Aktivieren des Auslösers beachtet werden muss: Beide erfordern eine gewisse Menge an Sperr- und Übertragungsaktivität. Beide Optionen erhöhen das Konfliktpotential, wenn auch nur geringfügig. Die beiden "Kontext" -Optionen sollten leichter sein / nur Speicher enthalten.


context_info ist ein Schmerzmittel. Wenn Sie eine Produktionsdatenänderung durchführen möchten, ist dies praktisch. Insbesondere das Deaktivieren des Auslösers kann dazu führen, dass andere Vorgänge den Auslöser nicht auslösen.
Biju Jose
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.