web-dev-qa-db-fra.com

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

Je travaille sur SQL Server 2008 R2.

J'ai une table avantage 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

15
srh

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, j'ai uniquement mis en évidence et exécuté le BEGIN TRANSACTION et le DISABLE TRIGGER première. J'ai ensuite ouvert une nouvelle (seconde) fenêtre de requête et essayé d'exécuter diverses instructions DML (SELECT, INSERT, UPDATEDELETE) sur 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.

6
Scott Hodgin

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 de variable du Context_info fonction et il passera à la partie d'échappement du déclencheur à la place.

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 dernier livre - Requête T-SQL . Le principal problème avec cela sur le context_info est la surcharge mineure 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
18
Shaulinator

J'utiliserais soit CONTEXT_INFO Soit le nouveau SESSION_CONTEXT. Les deux sont des valeurs basées sur la session.

  • CONTEXT_INFO Est une seule valeur VARBINARY(128). Celui-ci est disponible depuis au moins SQL Server 2000. CONTEXT_INFO Est visible par toute personne disposant de VIEW SERVER STATE Car il s'agit d'un champ renvoyé par le DMV sys.dm_exec_sessions. J'ai déjà utilisé celui-ci et il fonctionne plutôt bien.

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

    Selon le type de valeur que vous stockez dans CONTEXT_INFO, Certaines nuances doivent être prises 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 clé/valeur de valeurs SQL_VARIANT. 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 de désactivation/activation du 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.

2
Solomon Rutzky