SQL Server: comment désactiver le déclencheur d'une mise à jour uniquement pour votre session actuelle?


15

Je travaille sur SQL Server 2008 R2.

J'ai un avantage de table qui a un déclencheur AFTER INSERT, UPDATE nommé tiu_benefit .

Je veux écrire une instruction UPDATE pour que cette table mette à jour 1 ligne mais je ne veux pas que son déclencheur se déclenche. Je sais que je peux désactiver le déclencheur avant UPDATE, puis activer le déclencheur après UPDATE:

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

Mais ce déclencheur de désactivation et d'activation affectera tous les utilisateurs connectés actuellement. Il est donc possible qu'un autre utilisateur exécute une MISE À JOUR / INSÉRER alors que le déclencheur est désactivé par mon script, ce qui n'est pas bon. C'est pourquoi je veux seulement désactiver et activer le déclencheur pour ma session actuelle. C'est possible? Si oui, dites comment.

Merci


1
Si vous ne pouvez pas modifier votre déclencheur, la réponse est non.
jyao

Réponses:


6

J'ai fait quelques tests à ce sujet et je pense que vous iriez bien si vous exécutez votre processus en une seule transaction.

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 

Lors de mes tests, je n'ai mis en évidence et exécuté BEGIN TRANSACTIONque le DISABLE TRIGGERpremier. Je puis ouvert une nouvelle (seconde) fenêtre de requête et tenté d'exécuter diverses déclarations DML ( SELECT, INSERT, UPDATE DELETE) contre la table de base. Toutes les tentatives d'accès à la table de base dans la deuxième fenêtre de requête ont attendu les verrous détenus par la fenêtre avec la transaction explicite. Une fois que j'ai validé (ou annulé) ma transaction explicite, la deuxième fenêtre a pu accéder à la table.


Cela fonctionnera, mais les verrous peuvent provoquer des problèmes involontaires en aval, selon la durée pendant laquelle la transaction reste ouverte.
CaM

@CaM - Je suppose qu'une mise à jour d'une ligne ne prendrait pas trop de temps en supposant que l'OP valide ou annule rapidement la transaction. Espérons qu'il existe un indice sur benefit_id:)
Scott Hodgin

J'ai vraiment aimé cette solution car je n'ai pas à modifier le déclencheur
srh

18

Pour résoudre votre problème, nous devons adopter une approche programmatique du problème. Il y a deux itinéraires que vous pouvez emprunter ici. La raison pour laquelle ces approches sont nécessaires est que vous ne pouvez pas désactiver un déclencheur pour une instruction particulière, il ne peut être désactivé que pour l'intégralité du tableau.

Option 1: Context_Info ()

Samuel Vanga sur MS SQL Tips avait un excellent exemple:

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

Maintenant, quand Samuel ne veut pas que le déclencheur s'exécute, ils utilisent ceci:

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

Context_Info utilise les vues système suivantes pour récupérer des informations concernant la session en cours:

  • sys.dm_exec_requests

  • sys.dm_exec_sessions

  • sys.sysprocesses

L'idéologie ici est que la chaîne binaire que vous définissez n'est exposée qu'à la session en cours, donc lorsque le déclencheur s'exécute pendant votre session, il verra la portée et le paramètre variable de la Context_infofonction et passera à la partie d'échappement du déclencheur. au lieu.

Option 2: Tableau des températures

Itzik Ben-Gan a une excellente solution dans son livre "Inside Microsoft SQL Server 2008 Programmation T-SQL: Programmation T-SQL" qui est également dans son livre T-SQL Querying . Le principal problème avec cela sur la context_infofonction est le surdébit mineur de TempDB.

Pour gâcher la surprise mais ne pas gâcher l'intrigue des livres (j'ai senti qu'ils valent la peine d'être achetés et lus), vous allez modifier votre déclencheur.

Votre déclencheur doit effectuer une vérification pour une table temporaire. Si la table temporaire existe, le déclencheur doit savoir se terminer et ne pas effectuer les actions.

Dans l'instruction de mise à jour que vous souhaitez effectuer, créez d'abord la table temporaire. Il apparaîtra dans la même transaction que le déclencheur et entraînera le déclencheur à ignorer votre instruction.

Exemple de déclencheur:

CREATE TRIGGER TRIGGERNAME ON TABLENAME for INSERT AS

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

Exemple d'instruction de début lorsque vous ne voulez pas que le déclencheur s'exécute:

CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);

Mettre tout à fait pour votre exemple:

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
J'utiliserais context_info () au lieu de la table temporaire dans le déclencheur. Dans un autre mot, si un déclencheur détecte que context_info renvoie une valeur spécifique, le déclencheur fonctionnera en conséquence. Vous pouvez renvoyer la question SO pertinente ici: stackoverflow.com/questions/3025662/…
jyao

1
Vous pouvez également effectuer une vérification similaire à l' context_infoutilisation original_login()pour indiquer au déclencheur de ne jamais s'exécuter si une personne spécifique appuie sur le déclencheur.
Kenneth Fisher

2

J'utiliserais l'un CONTEXT_INFOou l' autre ou le plus récent SESSION_CONTEXT. Les deux sont des valeurs basées sur la session.

  • CONTEXT_INFOest une VARBINARY(128)valeur unique . Celui-ci est disponible depuis au moins SQL Server 2000. CONTEXT_INFOest visible par tout le monde VIEW SERVER STATEcar il s'agit d'un champ renvoyé par le sys.dm_exec_sessionsDMV. J'ai déjà utilisé celui-ci et il fonctionne très bien.

    Définir via SET CONTEXT_INFO
    Obtenir via CONTEXT_INFO () ou sys.dm_exec_sessions

    Selon le type de valeur que vous stockez CONTEXT_INFO, il y a quelques nuances à prendre en compte. Je couvre cela dans le blog suivant:

    Pourquoi CONTEXT_INFO () ne renvoie-t-il pas la valeur exacte définie par SET CONTEXT_INFO?

  • Session_context est une paire de SQL_VARIANTvaleurs clé / valeur . Cela a été introduit dans SQL Server 2016. La séparation des valeurs à des fins différentes est assez agréable. Session_context n'est visible que par la session en cours.

    Définissez cette valeur via sp_set_session_context
    Obtenez cette valeur via SESSION_CONTEXT

Une chose à considérer concernant l'option de table temporaire locale et même l'option désactiver / activer le déclencheur: les deux nécessitent une certaine quantité de verrouillage et d'activité du journal de transfert. Ces deux options augmentent le potentiel de contention, même minime. Les deux options "contextuelles" doivent être plus légères / mémoire uniquement.


context_info est un analgésique, chaque fois que vous souhaitez exécuter une modification des données de production, cela est pratique, en particulier la désactivation du déclencheur peut empêcher d'autres opérations de déclencher le déclencheur.
Biju jose
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.