web-dev-qa-db-fra.com

Existe-t-il un moyen de désactiver un déclencheur SQL Server pour un seul domaine d'exécution?

Dans SQL Server 2005, existe-t-il un moyen pour un déclencheur de déterminer quel objet est responsable de l'activation du déclencheur? J'aimerais utiliser ceci pour désactiver le déclencheur d'un produit stocké.

Existe-t-il un autre moyen de désactiver le déclencheur uniquement pour la transaction en cours? Je pourrais utiliser le code suivant, mais si je ne me trompe pas, cela affecterait également les transactions simultanées - ce qui serait une mauvaise chose.

DISABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ]

ENABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ]

Si possible, j'aimerais éviter la technique consistant à avoir un champ "NoTrigger" dans ma table et à faire un NoTrigger = null, car j'aimerais garder la table aussi petite que possible.

Si je souhaite éviter le déclencheur, c'est parce qu'il contient une logique importante pour les mises à jour manuelles de la table, mais ma procédure stockée s'en occupe. Parce que ce sera une procédure très utilisée, je veux qu’elle soit rapide.

Les déclencheurs imposent une surcharge supplémentaire au serveur car ils initient une transaction implicite. Dès qu'un déclencheur est exécuté, une nouvelle transaction implicite est démarrée et toute récupération de données dans une transaction maintiendra les verrous sur les tables affectées.

De: http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1170220,00.html#trigger

35
Seibar

Je viens de voir cet article récemment mis en évidence dans la lettre d'information SQL Server Central et il semble offrir un moyen que vous pouvez trouver utile en utilisant le Context_Info sur la connexion:

http://www.mssqltips.com/tip.asp?tip=1591


EDIT par Terrapin:

Le lien ci-dessus inclut le code suivant:

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  

Si vous souhaitez empêcher l'exécution du déclencheur, vous pouvez procéder comme suit:

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

Si votre déclencheur cause des problèmes de performances dans votre application, la meilleure approche consiste à supprimer toutes les mises à jour manuelles de la table et à exiger que toutes les mises à jour passent par les procédures stockées insertion/mise à jour contenant la logique de mise à jour correcte. Ensuite, vous pouvez supprimer complètement la gâchette. 

Je suggère de refuser les autorisations de mise à jour de table si rien d'autre ne fonctionne.

Cela résout également le problème du code en double. La duplication de code dans la mise à jour SP et dans le déclencheur enfreint les principes de base du génie logiciel et constitue un problème de maintenance.

6

ALTER TABLE tbl DISABLE TRIGGER trg

http://doc.ddart.net/mssql/sql70/aa-az_5.htm

Je ne comprends pas le sens de votre premier paragraphe si

4
devio

Je ne suis pas sûr que ce soit une bonne idée, mais cela semble fonctionner pour moi. La transaction devrait empêcher les insertions dans la table d'autres processus lorsque le déclencheur est désactivé.

IF OBJECT_ID('dbo.TriggerTest') IS NOT NULL
 DROP PROCEDURE dbo.TriggerTest
GO

CREATE PROCEDURE [dbo].[TriggerTest]
AS
BEGIN TRANSACTION trnInsertTable1s
;
DISABLE TRIGGER trg_tblTable1_IU ON tblTable1
;
BEGIN -- Procedure Code
    PRINT '@@trancount'
    PRINT @@TRANCOUNT
    -- Do Stuff

END -- Procedure Code
;
ENABLE TRIGGER trg_tblTable1_IU ON tblTable1

IF @@ERROR <> 0 ROLLBACK TRANSACTION
ELSE COMMIT TRANSACTION
2
Steve

Etant donné que vous indiquez que le déclencheur contient une logique permettant de gérer toutes les mises à jour, même les mises à jour manuelles, la logique doit alors être à la place. L'exemple que vous mentionnez, dans lequel une procédure stockée "prendra en charge cette logique" implique un code en double. De plus, si vous voulez être sûr que cette logique est appliquée à chaque instruction UPDATE, quel que soit son auteur, le déclencheur en est l'emplacement. Que se passe-t-il lorsque quelqu'un crée une procédure mais oublie de dupliquer la logique? Que se passe-t-il quand il est temps de modifier la logique?

2
Pittsburgh DBA

J'ai gaffé un peu sur celui-ci. D'un côté, je suis très anti-déclencheur surtout parce que c'est un endroit de plus pour moi de rechercher du code s'exécutant contre ma table, en plus des raisons énoncées dans l'article lié à la question. 

D'autre part, si vous avez la logique d'imposer des règles métier stables et immuables ou des actions inter-tables (comme maintenir une table d'historique), il serait alors plus sûr d'intégrer cela dans un déclencheur afin que les auteurs de procédures et les programmeurs n'aient pas à traiter avec ça - ça marche. 

Donc, ma recommandation est de mettre la logique nécessaire dans votre déclencheur plutôt que dans celui-ci, qui, inévitablement, passera à plusieurs processus avec la même exemption.

1
Rob Allen

Pensez à réécrire le déclencheur pour améliorer les performances si le problème est lié aux performances.

1
HLGEM

Ne désactivez pas le déclencheur. Vous avez raison, cela désactivera toutes les transactions simultanées.

Pourquoi voulez-vous désactiver le déclencheur? Qu'est ce que ça fait? POURQUOI la gâchette pose-t-elle un problème? Il est généralement déconseillé de désactiver un tigger du point de vue de l’intégrité des données. 

1
HLGEM

Je viens juste de faire face au même problème et de proposer la solution suivante, qui fonctionne pour moi.

  1. Créez une table de base de données permanente contenant un enregistrement pour chaque déclencheur que vous souhaitez désactiver (par exemple, refTriggerManager); chaque ligne contient le nom du déclencheur (par exemple, strTriggerName = 'myTrigger') et un indicateur de bit (par exemple, blnDisabled, par défaut à 0).

  2. Au début du corps du déclencheur, recherchez strTriggerName = 'myTrigger' dans refTriggerManager. Si blnDisabled = 1, retournez sans exécuter le reste du code de déclenchement, sinon continuez-le jusqu'au bout. 

  3. Dans le processus stocké dans lequel vous souhaitez désactiver le déclencheur, procédez comme suit:


COMMENCER LA TRANSACTION

MISE À JOUR refTriggerManager SET blnDisabled = 1 WHERE strTriggerName = 'myTrigger'

/ * UPDATE la table qui possède 'myTrigger' mais que vous souhaitez désactiver. Puisque refTriggerManager.blnDisabled = 1, 'myTrigger' est renvoyé sans exécuter son code. * /

MISE À JOUR refTriggerManager SET blnDisabled = 0 WHERE triggerName = 'myTrigger'

/ * Code UPDATE final facultatif qui déclenche le déclencheur. Puisque refTriggerManager.blnDisabled = 0, "myTrigger" est exécuté intégralement. * /

COMMIT TRANSACTION


Tout cela se passe dans une transaction, elle est donc isolée du monde extérieur et n'affectera pas les autres mises à jour de la table cible.

Est-ce que quelqu'un voit un problème avec cette approche?

Facture

0
Hoyacoder

Je suis d'accord avec d'autres réponses. Ne désactivez pas le déclencheur.

C'est de la pure opinion, mais j'évite les déclencheurs comme la peste. J'ai trouvé très peu de cas où un déclencheur était utilisé pour appliquer les règles de base de données. D'après mon expérience, il y a des cas évidents dans Edge, et je n'ai que mon expérience pour faire cette déclaration. J'ai généralement vu des déclencheurs utilisés pour insérer des données relationnelles (ce qui devrait être effectué à partir de la logique métier), pour insérer des données dans un tableau de reporting, c.-à-d. Dénormaliser les données (ce qui peut être fait avec un processus en dehors de la transaction) ou pour transformer les données. en quelque sorte. 

Il existe des utilisations légitimes pour les déclencheurs, mais je pense que dans la programmation professionnelle quotidienne, ils sont peu nombreux et espacés. Cela ne vous aidera peut-être pas à résoudre votre problème actuel, mais vous pouvez envisager de supprimer complètement le déclencheur et d'accomplir le travail que ce dernier effectue d'une autre manière.

0
Jason Jackson

vous pouvez utiliser la fonction 'Exec' pour désactiver et activer les déclencheurs à partir d'une procédure stockée. Exemple: EXEC ('ENABLE TRIGGER dbo.TriggerName on dbo.TriggeredTable')

0
Nader Sghir