17

我试图找出是否应该在数据库内部的触发器或约束中使用业务关键逻辑。
到目前为止,我已经在触发器中添加了逻辑,因为它让我可以控制接下来发生的事情,这意味着我可以提供自定义用户消息,而不是可能会混淆用户的错误。

在触发器上使用约束是否有任何显着的性能提升,以及确定使用哪个的最佳实践是什么。

4

12 回答 12

15

约束放手!

  • 通过约束,您可以指定关系原则,即关于您的数据的事实。除非某些事实发生变化(即新要求),否则您将永远不需要更改约束。

  • 使用触发器,您可以指定如何处理数据(在插入、更新等中)。这是一种“非关系”的做事方式。

用一个比喻来更好地解释我自己:编写 SQL 查询的正确方法是指定“你想要什么”而不是“如何得到它”——让 RDBMS 为你找出最好的方法。这同样适用于这里:如果你使用触发器,你必须记住各种事情,比如执行顺序、级联等……如果可能的话,让 SQL 为你做这件事。

这并不是说触发器没有用处。他们这样做:有时您不能使用约束来指定有关数据的某些事实。不过,这非常罕见。如果它经常发生在您身上,那么架构可能存在一些问题。

于 2008-09-29T10:25:39.483 回答
13

最佳实践:如果您可以使用约束来做到这一点,请使用约束。

触发器并不像它们被抹黑的那么糟糕(如果使用得当的话),尽管我总是尽可能地使用约束。在现代 RDMS 中,触发器的性能开销与约束相当(当然,这并不意味着有人不能在触发器中放置可怕的代码!)。

有时需要使用触发器来强制执行“复杂”约束,例如想要强制填充表的两个外键字段中的一个且只有一个的情况(我在一些域模型中看到过这种情况)。

关于业务逻辑是否应该驻留在应用程序而不是数据库中的争论在一定程度上取决于环境;如果您有许多应用程序访问数据库,则约束和触发器都可以作为数据正确的最终保护。

于 2008-09-29T10:10:27.663 回答
7

触发器可能会演变成性能问题。大约在发生这种情况的同时,它们也成为维护的噩梦。您无法弄清楚发生了什么,并且(奖励!)应用程序的行为不正常,出现“虚假”数据问题。[真的,它们是触发问题。]

没有最终用户直接接触 SQL。他们使用应用程序。应用程序以比触发器更智能、更易于维护的方式包含业务逻辑。将应用逻辑放在应用程序中。将数据放入数据库。

除非您和您的“用户”不使用共同语言,否则您可以向他们解释违反约束的情况。另一种选择——不解释——将一个简单的数据库变成一个问题,因为它将数据和应用程序代码混为一谈,成为一个无法维护的泥潭。

“我如何绝对保证每个人都在正确使用数据模型?”

两种(半)技术。

  1. 确保模型是正确的:它与现实世界的问题域相匹配。没有只能通过复杂的挥手解释、存储过程和触发器来整理的黑客或解决方法或捷径。

  2. 帮助定义应用程序的业务模型层。每个人共享和重用的应用程序代码层。

    一种。另外,确保模型层满足人们的需求。如果模型层有正确的方法和集合,那么绕过它直接访问底层数据的动机就会减少。一般来说,如果模型是正确的,这不是一个严重的问题。

触发器是等待发生的火车残骸。约束不是。

于 2008-09-29T10:02:10.677 回答
7

除了使用约束的其他原因之外,Oracle 优化器还可以利用约束来发挥其优势。

例如,如果你有一个约束说(Amount >= 0),然后你用WHERE (Amount = -5)Oracle 查询立即知道没有匹配的行。

于 2008-11-12T23:01:03.350 回答
5

约束和触发器用于 2 个不同的事物。约束用于约束数据的域(有效输入)。例如,SSN 将存储为 char(9),但具有 [0-9][0-9][0-9][0-9][0-9][0-9][ 0-9][0-9][0-9](全数字)。

触发器是在数据库中执行业务逻辑的一种方式。再次使用 SSN,也许每当 SSN 发生更改时都需要维护审计跟踪 - 这将通过触发器来完成,

一般来说,现代 RDBMS 中的数据完整性问题可以通过约束的某些变化来处理。但是,您有时会遇到不正确的规范化(或更改的要求,导致现在不正确的规范化)阻止约束的情况。在这种情况下,触发器可能能够强制执行您的约束 - 但它对 RDBMS 是不透明的,这意味着它不能用于优化。这也是“隐藏”的逻辑,可能是一个维护问题。决定是重构模式还是使用触发器是此时的判断调用。

于 2008-09-29T11:04:29.873 回答
4

一般来说,我更喜欢约束,我的代码会捕获 sql server 错误并为用户提供更友好的内容。

于 2008-09-29T09:59:30.420 回答
3

@onedaywhen

您可以在 SQL Server 中将查询作为约束,您只需能够将其放入标量函数中:http://www.eggheadcafe.com/software/aspnet/30056435/check-contraints-and-tsql。 aspx

于 2008-10-01T21:43:42.347 回答
2

如果有可能使用约束。他们往往更快。触发器应该用于约束无法处理的复杂逻辑。触发器编写也很棘手,如果您发现必须编写触发器,请确保使用基于集合的语句,因为触发器针对整个插入、更新或删除操作(是的,有时会影响多个记录,计划在那!),而不仅仅是一次记录。如果可以避免,请不要在触发器中使用游标。

至于是否将逻辑放在应用程序中而不是触发器或约束中。不要那样做!!!是的,应用程序在发送数据之前应该进行检查,但是数据完整性和业务逻辑必须在数据库级别,否则当多个应用程序挂钩时,当在应用程序外部完成全局插入等时,您的数据会变得混乱。数据完整性是数据库的关键,必须在数据库级别强制执行。

于 2008-09-29T13:21:04.537 回答
2

@Mark Brackett:“约束用于约束域......触发器是执行业务逻辑的一种方式”:在 SQL Server 中并不是那么简单,因为它的约束功能受到限制,例如尚未完整的 SQL-92。以时态数据库表中有序“主键”的经典示例为例:理想情况下,我会使用带有子查询的 CHECK 约束来防止同一实体的重叠时间段,但 SQL Server 不能这样做,所以我必须使用扳机。SQL Server 还缺少 SQL-92 延迟检查约束的能力,而是在每个 SQL 语句之后(实际上)检查它们,因此可能需要再次使用触发器来解决 SQL Server 的限制。

于 2008-09-29T13:58:28.253 回答
1

@Meff:使用函数的方法存在潜在问题,因为简单地说,SQL Server CHECK 约束被设计为以单行作为工作单元,并且在处理结果集时存在缺陷。有关这方面的更多详细信息,请参阅:[ http://blogs.conchango.com/davidportas/archive/2007/02/19/Trouble-with-CHECK-Constraints.aspx][1]

[1]:David Portas 的博客:CHECK 约束的问题。

于 2008-10-02T10:11:03.050 回答
1

与斯克利兹相同。只是为了让您知道触发器的规范用法是审计表。如果许多程序更新/插入/删除您要审计的表(谁修改了什么以及何时),触发器是最简单的方法。一种方法是简单地在你的表中添加一个标志(活动/非活动与一些唯一性约束)并在审计表中插入一些东西。

如果您希望表不保存历史数据,另一种方法是复制审计表中的前一行...

许多人有很多方法可以做到这一点。但有一件事是肯定的,您必须为此表中的每个更新/插入/删除执行插入

为了避免在十几个不同的地方写入插入,您可以在此处使用触发器。

于 2014-01-09T08:22:59.323 回答
0

我同意这里的每个人关于约束的看法。尽可能多地使用它们。

存在过度使用触发器的趋势,尤其是对于新开发人员。我见过一个触发器触发另一个触发器的情况,该触发器触发另一个触发器,该触发器重复第一个触发器,从而创建一个绑定您的服务器的级联触发器。这是触发器的非最佳用户;o)

话虽如此,触发器有它们的位置,应该在适当的时候使用。它们特别适合跟踪数据的变化(正如 Mark Brackett 所提到的)。您需要回答“将我的业务逻辑放在哪里最有意义”的问题?大多数时候我认为它属于代码,但你必须保持开放的心态。

于 2008-09-29T13:00:54.353 回答