Sql server 是否有一种方法可以仅对特定的执行范围禁用SQL Server触发器?

Sql server 是否有一种方法可以仅对特定的执行范围禁用SQL Server触发器?,sql-server,tsql,triggers,Sql Server,Tsql,Triggers,在SQLServer2005中,有没有一种方法可以让触发器找出触发触发器的对象?我想用它来禁用一个存储过程的触发器 是否有其他方法仅对当前事务禁用触发器?我可以使用下面的代码,但如果我没有弄错的话,它也会影响并发事务——这将是一件坏事 DISABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ] ENABLE TRIGGER

在SQLServer2005中,有没有一种方法可以让触发器找出触发触发器的对象?我想用它来禁用一个存储过程的触发器

是否有其他方法仅对当前事务禁用触发器?我可以使用下面的代码,但如果我没有弄错的话,它也会影响并发事务——这将是一件坏事

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 } [ ; ]
如果可能,我希望避免在表中使用“NoTrigger”字段并执行
NoTrigger=null
,因为我希望表尽可能小

我之所以要避免触发器,是因为它包含对手动更新表很重要的逻辑,但我的存储过程将处理此逻辑。因为这将是一个高度使用的过程,我希望它是快速的

触发器会在服务器上增加额外开销,因为它们会启动隐式事务。一旦执行触发器,就会启动一个新的隐式事务,并且事务中的任何数据检索都将在受影响的表上保持锁


From:

更改表tbl禁用触发器训练


我不明白你第一段的意思,尽管不要禁用触发器。您将禁用任何并发事务,这是正确的


为什么要禁用触发器?它有什么作用?为什么触发器会引发问题?从数据完整性的角度来看,禁用跳跳虎通常不是一个好主意

如果触发器导致应用程序出现性能问题,那么最好的方法是删除对表的所有手动更新,并要求所有更新都经过包含正确更新逻辑的insert/update存储过程。然后,您可以完全卸下触发器

我建议如果没有其他办法,就拒绝表更新权限


这也解决了重复代码的问题。在更新SP和触发器中复制代码违反了良好的软件工程原则,这将是一个维护问题。

因为您指出触发器包含处理所有更新(甚至手动更新)的逻辑,所以这应该是逻辑所在的位置。您提到的示例中,存储过程“将处理此逻辑”意味着重复代码。此外,如果您想确保每个UPDATE语句都应用了此逻辑,而不考虑作者,那么触发器就是它的位置。如果有人编写了一个过程,但又忘记复制逻辑,会发生什么?当需要修改逻辑时会发生什么情况?

如果是性能问题,请考虑重写触发器以提高性能。

我同意其他一些答案。不要禁用触发器

这是纯粹的观点,但我避免像瘟疫这样的触发因素。我发现很少有使用触发器强制执行数据库规则的情况。在我的经验中,有一些明显的边缘案例,我只有我的经验来做这个陈述。我通常看到触发器用于插入一些关系数据(应该从业务逻辑中执行)、将数据插入到报告表中(即数据非规范化)(可以通过事务之外的流程执行),或者以某种方式转换数据


触发器是有合法用途的,但我认为在日常业务编程中,触发器的用途很少。这可能对你当前的问题没有帮助,但是你可以考虑完全删除触发器,完成触发器正在以其他方式做的工作。一方面,我非常反对触发器,这主要是因为除了问题帖子中链接的文章中所述的原因之外,这是我寻找针对我的表执行的代码的又一个地方

另一方面,如果您有逻辑来强制执行稳定且不可变的业务规则或跨表操作(如维护历史记录表),那么将其放入触发器中会更安全,这样过程作者和程序员就不需要处理它——它只会工作


所以,我的建议是把必要的逻辑放在触发器中,而不是放在这个过程中,将不可避免地增长到具有相同豁免的多个过程。

我最近在SQL Server Central新闻稿上看到了这篇文章,它似乎提供了一种方法,您可以使用连接的上下文信息发现这一方法很有用:


按Terrapin编辑:

上述链接包括以下代码:

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  
如果要防止执行触发器,可以执行以下操作:

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

我只是遇到了同样的问题,并提出了以下解决方案,这对我来说是可行的

  • 创建一个永久数据库表,其中包含要禁用的每个触发器的一条记录(例如refTriggerManager);每行包含触发器名称(例如strTriggerName='myTrigger')和位标志(例如blnDisabled,默认为0)

  • 在触发器主体的开头,在refTriggerManager中查找strTriggerName='myTrigger'。如果blnDisabled=1,则返回而不执行其余的触发器代码,否则继续执行触发器代码直至完成

  • 在要禁用触发器的存储过程中,执行以下操作:

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

    开始交易

    更新refTriggerManager集blnDisabled=1,其中strTriggerName='myTrigger'

    /*更新拥有“myTrigger”但希望禁用的表。由于refTriggerManager.blnDisabled=1,“myTrigger”返回时不执行其代码*/

    更新refTriggerManager集blnDisabled=0,其中triggerName='myTrigger'

    /*触发触发器的可选最终更新代码。由于refTriggerManager.blnDisabled=0,“myTrigger”将完全执行*