数据库触发器

时间:2020-03-05 18:40:14  来源:igfitidea点击:

过去,我从来都不喜欢在数据库表上使用触发器。在我看来,它们始终代表着数据库方面将要发生的"魔术",与我的应用程序代码的控制相距甚远。我还想限制数据库必须完成的工作量,因为它通常是共享资源,而且我一直认为触发器在高负载情况下可能会变得昂贵。

就是说,我发现了一些使用触发器有意义的实例(至少在我看来它们是有意义的)。但是最近,我发现自己有时会需要"绕过"触发器。对于必须寻找实现此目标的方法,我感到内,并且我仍然认为,更好的数据库设计可以减轻这种绕过的需要。不幸的是,这个数据库被多个应用程序使用,其中一些由非常不合作的开发团队维护,他们会大声疾呼架构更改,因此我陷入了困境。

关于触发器的一般共识是什么?爱他们吗?讨厌他们吗?认为它们在某些情况下可以达到目的吗?
是否认为需要绕过触发器就意味着我们"做错了"?

解决方案

回答

我热衷于使用HATE触发的Cand中的Web和Winforms应用程序工作。我从来没有遇到过这样的情况:我可以证明使用触发器,而不是将该逻辑移到应用程序的业务层并在那里复制触发器逻辑。

我没有做任何DTS类型的工作或者类似的事情,因此可能会有一些在其中使用触发器的用例,但是如果我的任何团队中的任何人都说他们可能想使用触发器,那么他们会更好地准备好论点因为我拒绝待命,而是将触发器添加到我正在处理的任何数据库中。

我不喜欢触发器的一些原因:

  • 他们将逻辑移入数据库。一旦开始这样做,我们就会感到痛苦,因为我们失去了调试,编译时间安全性和逻辑流程。都是下坡路。
  • 他们实现的逻辑对任何人都不容易看到。
  • 并非所有数据库引擎都支持触发器,因此解决方案会创建对数据库引擎的依赖关系

我敢肯定,我会想到更多其他原因,但仅凭这些,我就不用触发器了。

回答

我个人不是粉丝。我将使用它们,但是仅当我发现代码中的瓶颈时,可以通过将动作移至触发器来清除该瓶颈。通常,我更喜欢简单性,而保持简单性的一种方法是将逻辑保持在应用程序的某个位置。我还从事过访问非常隔离的工作。在这些环境中,我打包的代码越多,触发的人就越多,即使是最简单的修复程序,我也需要投入更多的人。

回答

我发现自己在进行批量数据导入时会绕过触发器。我认为在这种情况下是合理的。

但是,如果最终却经常绕过触发器,则可能首先需要看看将触发器放置在什么地方。

总的来说,我会投票赞成"它们在某些情况下能达到目的"。我一直对性能影响感到不安。

回答

触发器可以非常有帮助。它们也可能非常危险。我认为它们适用于房屋清洁任务,例如填充审核数据(创建日期,修改日期等),并且在某些数据库中可用于参照完整性。

但是我不喜欢在其中添加许多业务逻辑。这会使支持成为问题,因为:

  • 这是研究的额外代码层
  • 有时,正如OP所了解的那样,当我们需要进行数据修复时,触发器可能会在做事时假设数据更改始终是通过应用程序指令进行的,而不是通过开发人员或者DBA来解决问题的,甚至不是通过其他问题解决的应用程序

至于必须绕过触发器执行某项操作,这可能意味着我们做错了什么,或者可能意味着触发器做错了什么。

我喜欢与触发器一起使用的一般规则是保持触发器轻巧,快速,简单并且尽可能无创。

回答

几周前我第一次使用触发器。我们将生产服务器从SQL 2000切换到SQL 2005,我们发现驱动程序在NText字段(存储大型XML文档)方面表现有所不同,删除了最后一个字节。我使用触发器作为临时解决方案,在数据末尾添加了一个额外的虚拟字节(一个空格),解决了我们的问题,直到可以推出适当的解决方案为止。

除了这种特殊的临时情况外,我想避免使用它们,因为它们确实隐藏了正在发生的事情,并且它们提供的功能应该由开发人员显式处理,而不是作为某种隐藏的魔术来处理。

回答

每次调用数据库后,将其视为一个巨大的大对象,它应该处于逻辑上一致的状态。

数据库通过表公开自己,保持表和行的一致性可以通过触发器来完成。使它们保持一致的另一种方法是禁止直接访问表,而仅允许通过存储过程和视图进行访问。

触发器的缺点是任何动作都可以调用它们。这也是没有人会通过无能来破坏系统完整性的一种优势。

作为对策,仅允许通过存储过程和视图访问数据库仍然允许后门访问权限。信任具有足够权限的用户不会破坏数据库完整性,所有其他用户都使用存储过程。

关于减少工作量:当数据库不必与外界打交道时,它们的效率是惊人的。我们真的会感到惊讶,甚至过程切换也会严重损害性能。那是存储过程的另一个好处:不是一个十几次的数据库调用(以及所有相关的往返行程),而是一个。

Bunching stuff up in a single stored proc is fine, but what happens when something goes wrong? Say you have 5 steps and the first step fails, what happens to the other steps? You need to add a whole bunch of logic in there to cater for that situation. Once you start doing that you lose the benefits of the stored procedure in that scenario.

业务逻辑必须走到什么地方,数据库关系的设计中嵌入了许多隐含的域规则,约束等都是通过例如说用户只能拥有一个密码来整理业务规则的尝试。既然已经开始通过具有这些关系等将业务规则推到数据库服务器上,那么我们在哪里划清界限?数据库什么时候放弃对数据完整性的责任,并开始信任调用应用程序和数据库用户以正确处理数据?嵌入了这些规则的存储过程可以将很多政治权力推入DBA手中。这取决于n层体系结构中将要存在多少层。如果存在表示,业务和数据层,那么业务和数据之间的分隔在哪里?业务层会增加什么增值?我们是否将数据库服务器上的业务层作为存储过程运行?

是的,我认为必须绕过触发器才意味着我们"做错了"。在这种情况下,触发器不适合我们。

回答

老实说,只有我使用触发器来模拟唯一索引,该索引允许具有不计入唯一性的NULL。

回答

As to reducing the amount of work: databases are stunningly efficient when they don't have to deal with the outside world; you'd be really surprised how much even process switching hurts performance. That's another upside of stored procedures: rather than a dozen calls to the database (and all the associated round trips), there's one.

这是一个有点题外话,但我们还应该意识到,我们只是从一个潜在的积极方面着眼。

将内容打包在一个存储的proc中很好,但是当出现问题时会发生什么呢?假设我们有5个步骤,而第一步失败了,那么其他步骤会怎样?我们需要在其中添加一堆逻辑来解决这种情况。一旦开始这样做,我们将失去该方案中存储过程的好处。

回答

风扇总数

但确实必须在某些时候谨慎使用,

  • 需要保持一致性(尤其是在仓库中使用维度表时,我们需要将事实表中的数据与其正确的维度相关联。有时,维度表中的正确行可能非常昂贵,因此我们需要键直接写入事实表,保持"关系"的一种好方法是使用触发器。
  • 需要记录更改(例如,在审核表中,了解@@ user所做的更改以及更改的时间很有用)

一些RDBMS(例如sql server 2005)还为我们提供了CREATE / ALTER / DROP语句的触发器(因此我们可以知道谁创建了什么表,何时创建,删除了哪个列,何时等等)。

老实说,在这三种情况下使用触发器,我不明白为什么我们需要"禁用"它们。

回答

触发器通常使用不正确,会引入错误,因此应避免使用。切勿设计触发器来进行跨表中各行的完整性约束检查(例如,"按部门划分的平均薪水不能超过X")。

Oracle副总裁Tom Kyte表示,他希望删除触发器作为Oracle数据库的功能,因为触发器经常在bug中起作用。他知道这只是一个梦想,触发器仍然存在,但是如果他能从Oracle中删除触发器,他将(以及WHEN OTHERS子句和自主事务)。

Can triggers be used correctly?  Absolutely.
  
  The problem is - they are not used correctly in so
  many cases that I'd be willing to give
  up any perceived benefit just to get
  rid of the abuses (and bugs) caused by
  them. - Tom Kyte

回答

一般的经验法则是:不要使用触发器。如前所述,它们增加了开销和复杂性,通过将逻辑移出DB层可以轻松避免这些开销。

此外,在MS SQL Server中,触发器将针对每个sql命令触发一次,而不是针对每行触发一次。例如,以下sql语句将仅执行一次触发器。

UPDATE tblUsers
SET Age = 11
WHERE State = 'NY'

包括我自己在内的许多人都给每行触发触发器的印象,但事实并非如此。如果我们有一个上面的sql语句,它可能会更改一行以上的数据,则可能需要包括一个游标,以更新受触发器影响的所有记录。我们会看到如何很快将其弄乱。

回答

"绝对不要设计一个触发器来执行跨表中各行的完整性约束检查"-我不同意。该问题在SQL Server中被标记为" SQL Server"和" CHECK约束"子句,不能包含子查询。更糟糕的是,该实现似乎有一个"硬编码"假设,即CHECK仅涉及单个行,因此使用函数是不可靠的。因此,如果我需要一个确实包含多于一行的约束,并且一个很好的例子是经典的"有效时间"时态表中的排序主键,那么我需要防止同一实体的重叠时间段-我该怎么办没有触发?请记住,这是一个主键,可以确保我具有数据完整性,因此在DBMS之外的其他任何地方都无法实施它。在CHECK约束获得子查询之前,我看不到对某些类型的完整性约束使用触发器的替代方法。