SQL触发器以及何时或何时不使用它们。


43

当我最初学习SQL时,总是被告知,只有在确实需要时才使用触发器,并尽可能使用存储过程。

不幸的是,现在(几年前)我并不像现在这样好奇和关心基本面,因此从未问过为什么。

社区对此有何看法?仅仅是某人的个人喜好,还是应该避免触发(就像游标一样),除非有充分的理由。


Answers:


32

数据库触发器维基百科文章的礼物是什么触发器是一个很好的概述,当在不同的数据库使用它们。

以下讨论仅基于SQL Server。

当合理使用触发器时,使用触发器是非常有效的。例如,它们在审核(保留数据历史记录)方面具有很好的价值,而无需在每个表上的每个CRUD命令中都使用显式的过程代码。

触发器使您可以在数据更改之前和数据更改之后进行控制。这允许:

  • 如前所述审核
  • 验证和业务安全检查(如果需要)。由于这种类型的控件,您可以在插入数据库之前和之后执行列格式化等任务。

经常有人告诉我,只有在确实需要时才使用触发器,并尽可能使用存储过程。

可能是某些原因造成的:

  1. 现在,可以使用其他方式执行某些过去曾经触发的功能,例如更新总计和对列进行自动计算。
  2. 您不知道单独存在的代码就看不到触发器在哪里被调用。当您看到数据更改时,您会看到它们的效果,有时弄乱找出更改发生的原因,除非您知道表上有触发器或更多操作。
  3. 如果您在多个表上使用多个数据库控件(例如CHECK,RI,触发器),则您的交易明细流程将变得难以理解和维护。您将需要确切知道什么时候会发生。同样,您将需要良好的文档说明。

触发器和非触发器存储过程之间的一些区别(以及其他):

  • 非触发式存储过程就像一个程序,必须从代码,调度程序或批处理作业等中显式调用该程序来执行其工作,而触发器是一种特殊类型的存储过程,它会以事件的响应,而不是由用户直接执行。该事件例如可以是数据列中的数据改变。
  • 触发器具有类型。DDL触发器和DML触发器(类型:INSTEAD OF,For和AFTER)
  • 非触发器存储过程可以引用任何类型的对象,但是,要引用视图,必须使用INSTEAD OF触发器。
  • 在SQLServer中,非触发器存储过程可以有任意数量,但每个表只能有1个INSTEAD OF触发器。

8

触发器是任何复杂数据完整性规则的要求。除数据库以外的任何地方都无法强制执行这些命令,否则您将遇到数据完整性问题。

除非您不希望捕获对数据库的所有更改(这是从应用程序进行审核的问题),否则它们也是进行审核的最佳位置。

如果不仔细编写触发器,并且触发器的知识不足以充分编写触发器,则会导致性能问题。这是他们说唱不好的一部分。

触发器通常比维护数据完整性的其他方法慢,因此,如果可以使用检查约束,请使用它代替触发器。

很容易编写出不好的触发器来执行愚蠢的事情,例如尝试发送电子邮件。如果电子邮件服务器出现故障,您是否真的要无法更改数据库中的记录?

在SQL Server中,触发器对一批记录进行操作。开发人员经常认为他们只需要处理一条记录的插入,更新或删除。这不是发生在数据库上的唯一数据更改,并且应该在1条记录更改和许多条记录更改的条件下测试所有触发器。忘记进行第二项测试可能会导致触发器的执行效果极差或丢失数据完整性。


3

使用数据库触发器

  1. 自动驱动列值。
  2. 强制执行复杂的完整性约束。
  3. 强制执行复杂的业务规则。
  4. 自定义复杂的安全授权。
  5. 维护复制表。
  6. 审核数据修改。

2

我个人遇到的另一种用例是由多个程序访问的数据库。如果您想实现功能而不是重新设计所有系统,则触发器可以提供一个明智的解决方案。

例如,我最近在处理一个以前仅作为办公系统存在的数据库。当编写一个Webapp与之交互时,我们希望实现一个通知系统(例如,类似于stackexchange),该通知系统将由多个事件(例如处理交易等)触发。我们能够实现一个触发器,以便办公室后端的更新触发一个触发器来为前端创建通知,并告诉用户他们的交易已由办公室处理。


1

触发器可用于对数据库强制执行约束,而在数据库模式创建和任何DML语句执行期间不能强制执行触发器。


0

假设您需要近实时地将数据推送到第三方系统。您的表包含950 GB的数据,因此它太大了,无法仅将整个表推送到第三方应用程序。

相反,您将更改累积在队列中。然后,某些外部程序将定期推出少量的排队数据。

该系统具有2000多个存储过程。您还知道源代码中存在大量的sql。为了确保正确填充队列,您必须搜索所有存储的proc和代码,并希望您不要错过任何内容。

相反,您可以在表上放置触发器以保持队列更新。保证不会错过任何东西。一个中心位置。性能损失?并不是真的,因为无论是通过触发器还是外部,都无法避免填充队列的麻烦。

在这种情况下,我会说不使用触发器是一个错误的设计选择。如果以后要使用一种新的推送数据的方法(例如,队列未解决),并且使用触发器则可以保护接口更改。触发器通常是最佳选择。不要听教条主义的反触发迷们。


但是肯定有很多事情不应该使用触发器来实现。
Tydus勋爵,2011年

-6

发送电子邮件的触发器不一定是“愚蠢”的想法。愚蠢的是没有预料到设计中的电子邮件中断,并且会优雅地处理电子邮件而不会丢失数据。对于那些懒惰的开发人员来说,他们的“愚蠢”部分对于不存在的错误处理确实是不好的,他们认为自己可以避免犯错误。

我还将提供这样的观察:通过调用存储过程/函数可以使触发器保持简单,该存储过程/函数可以任意复杂,并且可以被多个触发器或其他存储过程重用。这就是为什么有包和库的原因。

偏执确实是残酷的。


1
我在问题中没有看到提到“电子邮件”一词的地方。您是否正在尝试回答另一个答案?Stack Exchange不是论坛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.