触发器与约束的性能注意事项
我试图找出是否应该在数据库内部的触发器或者约束中使用业务关键逻辑。
到目前为止,我已经在触发器中添加了逻辑,因为它使我可以控制接下来发生的事情,这意味着我可以提供自定义用户消息,而不是可能会使用户感到困惑的错误。
在触发器上使用约束以及在确定使用哪种最佳方法方面有什么显着的性能提升?
解决方案
一般来说,我更喜欢使用约束,并且我的代码会捕获sql服务器错误并向用户展示更友好的内容。
触发器会导致性能问题。大约在同一时间,它们也成为维护的噩梦。我们无法弄清楚发生了什么,并且(奖励!)应用程序在出现"虚假"数据问题时行为异常。 [确实,它们触发了问题。]
没有最终用户直接接触SQL。他们使用应用程序。与触发器相比,应用程序以更智能,更可维护的方式包含业务逻辑。将应用程序逻辑放入应用程序中。将数据放入数据库。
除非我们和"用户"没有共同的语言,否则我们可以向他们解释违反约束的情况。替代方法(没有说明)将一个简单的数据库变成一个问题,因为它将数据和应用程序代码混为一谈是无法维持的泥潭。
"如何绝对保证每个人都在正确使用数据模型?"
两种(半)技术。
- 确保模型正确:它与实际问题域匹配。没有任何只能通过复杂的挥手解释,存储过程和触发器来解决的黑客,变通方法或者快捷方式。
- 帮助定义应用程序的业务模型层。每个人都共享和重用的应用程序代码层。一种。另外,请确保模型层满足人们的需求。如果模型层具有正确的方法和集合,则绕过它来直接访问基础数据的动机就更少了。通常,如果模型是正确的,那么这并不是什么大问题。
触发器是等待发生的火车残骸。约束不是。
最佳实践:如果可以用约束来做到这一点,请使用约束。
尽管我会尽可能使用约束,但触发器并没有使它们失去信誉(如果正确使用)那样糟糕。在现代RDMS中,触发器的性能开销可与约束相比(当然,这并不意味着某人无法在触发器中放置可怕的代码!)。
有时,必须使用触发器来强制执行"复杂"约束,例如想要强制填充Table的两个外键字段中的一个且仅其中之一的情况(我已经在一些域模型中看到了这种情况)。
关于业务逻辑是否应该驻留在应用程序中而不是数据库中的争论,在某种程度上取决于环境;它在某种程度上取决于环境。如果我们有许多应用程序在访问数据库,则约束和触发器都可以作为最终保证数据正确。
束手无策!
- 在约束条件下,我们可以指定关系原则,即有关我们数据的事实。除非某些事实发生变化(即新要求),否则我们将不需要更改约束。
- 使用触发器,我们可以指定如何处理数据(插入,更新等)。这是一种"非关系"的做事方式。
用类比更好地说明自己:编写SQL查询的正确方法是指定"我们想要什么"而不是"如何获取",让RDBMS找出为我们完成此操作的最佳方法。同样适用于此:如果使用触发器,则必须牢记各种事情,例如执行顺序,级联等。如果可能的话,让SQL为我们做一些约束。
这并不是说触发器没有用处。它们做到了:有时我们不能使用约束来指定有关数据的某些事实。但是,这是极为罕见的。如果我们经常遇到这种情况,那么该架构可能存在一些问题。
约束和触发器是针对两种不同的事物的。约束用于约束数据的域(有效输入)。例如,一个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不透明,这意味着它不能用于优化。它也是"隐藏的"逻辑,可能是维护问题。决定是重构模式还是使用触发器是此时的判断调用。
我同意这里的所有人关于约束的观点。尽可能使用它们。
有一种过度使用触发器的趋势,特别是对于新开发人员。我已经看到一种情况,其中触发器触发另一个触发器,该触发器又触发另一个重复第一个触发器的触发器,从而创建一个级联触发器来绑定服务器。这是触发器的非最佳用户; o)
话虽如此,触发器才是他们应有的地位,应在适当时使用。它们特别适合跟踪数据的更改(如Mark Brackett所述)。我们需要回答"在哪里放置我的业务逻辑最有意义"的问题?大多数时候,我认为它属于代码,但是我们必须保持开放的态度。
如果可能的话,请使用约束条件。他们倾向于更快的发音。触发器应用于约束无法处理的复杂逻辑。触发器的编写也很棘手,如果发现必须编写触发器,请确保使用基于集合的语句,因为触发器会对整个插入,更新或者删除操作(是的,有时会影响多个记录,请计划!),而不仅仅是一次记录。如果可以避免,请勿在触发器中使用游标。
至于是否在应用程序中放置逻辑而不是触发器或者约束。不要那样做!!!是的,应用程序在发送数据之前应该进行检查,但是数据完整性和业务逻辑必须在数据库级别,否则当多个应用程序挂接到数据库中,全局插入超出应用程序等时,数据将被弄乱。完整性是数据库的关键,必须在数据库级别上执行。
@Mark Brackett:"约束用于约束域...触发器是执行业务逻辑的一种方式":在SQL Server中,它并不是那么简单,因为其约束的功能受到限制,例如。尚未完整的SQL-92. 以时间数据库表中序列化"主键"的经典示例为例:理想情况下,我将对子查询使用CHECK约束,以防止同一实体的重叠时间段,但是SQL Server无法做到这一点,因此我必须使用扳机。 SQL Server还缺少SQL-92的功能来推迟对约束的检查,但实际上在每个SQL语句之后都要对约束进行检查,因此可能需要再次触发才能解决SQL Server的限制。
@onedaywhen
我们可以将查询作为SQL Server中的约束,只需将其适合标量函数即可:http://www.eggheadcafe.com/software/aspnet/30056435/check-contraints-and-tsql。 aspx
@Meff:使用函数的方法存在潜在的问题,因为简单地说,SQL Server CHECK约束设计为以单行作为工作单位,并且在处理结果集时存在缺陷。有关此的更多详细信息,请参见:[http://blogs.conchango.com/davidportas/archive/2007/02/19/Trouble-with-CHECK-Constraints.aspx][1]。
[1]:David Portas的博客:CHECK约束问题。
除了使用约束的其他原因之外,Oracle优化器还可以使用约束来发挥其优势。
例如,如果我们有一个约束说"(Amount> = 0)",然后使用" WHERE(Amount = -5)"查询,Oracle会立即知道没有匹配的行。