Sql server 何时/为什么在SQL Server中使用级联?

Sql server 何时/为什么在SQL Server中使用级联?,sql-server,database-design,foreign-keys,rdbms,cascade,Sql Server,Database Design,Foreign Keys,Rdbms,Cascade,在SQL Server中设置外键时,在什么情况下应该在删除或更新时级联外键,其背后的原因是什么 这可能也适用于其他数据库 最重要的是,我正在寻找每个场景的具体示例,最好是来自成功使用它们的人。一个示例是当实体之间存在依赖关系时。。。ie:Document->DocumentItems(当您删除文档时,DocumentItems没有存在的理由)我试图避免在SQL server中未明确请求的删除或更新 通过级联或使用触发器。他们往往会在一段时间内咬你的屁股,无论是在试图追踪bug还是在诊断性能问题时

在SQL Server中设置外键时,在什么情况下应该在删除或更新时级联外键,其背后的原因是什么

这可能也适用于其他数据库


最重要的是,我正在寻找每个场景的具体示例,最好是来自成功使用它们的人。

一个示例是当实体之间存在依赖关系时。。。ie:Document->DocumentItems(当您删除文档时,DocumentItems没有存在的理由)

我试图避免在SQL server中未明确请求的删除或更新

通过级联或使用触发器。他们往往会在一段时间内咬你的屁股,无论是在试图追踪bug还是在诊断性能问题时


我将使用它们的地方是保证一致性,而不是付出太多的努力。要获得相同的效果,必须使用存储过程。

我从不使用级联删除

如果我想从数据库中删除一些东西,我想明确地告诉数据库我想删除什么

当然,它们是数据库中可用的函数,有时可以使用它们,例如,如果您有一个“order”表和一个“orderItem”表,则在删除订单时可能需要清除这些项

我喜欢通过代码(或存储过程)而不是通过“魔术”实现的清晰性

出于同样的原因,我也不喜欢触发器


需要注意的是,如果您确实删除了一个“订单”,即使级联删除删除了50个“orderItem”,也会返回“1行受影响”报告

外键是确保数据库引用完整性的最佳方法。由于具有魔力而避免级联就像在汇编中编写所有东西一样,因为您不相信编译器背后的魔力

坏的是外键的错误使用,例如,向后创建外键

Juan Manuel的例子就是一个典型的例子,如果您使用代码,那么在数据库中留下虚假文档项的可能性会更大,而这些虚假文档项会攻击您

级联更新非常有用,例如,当您通过可以更改的内容引用数据时,例如用户表的主键是名称、lastname组合。然后,您希望该组合中的更改传播到引用它们的任何地方


@艾丹,你所说的清晰是要付出高昂的代价的,在你的数据库中留下虚假数据的可能性不小。对我来说,通常只是缺乏对DB的熟悉,在与DB合作之前无法发现哪些FK已经就位,这助长了这种恐惧。要么就是这样,要么就是不断滥用级联,在实体概念上不相关的地方使用它,或者在必须保存历史的地方使用它。

我做了大量的数据库工作,很少发现级联删除有用。我有效地使用它们的一次是在一个由夜间作业更新的报告数据库中。我通过删除自上次导入以来已更改的任何顶级记录,然后重新导入修改后的记录以及与之相关的任何内容,确保正确导入任何更改的数据。它使我不必编写大量从数据库底部到顶部的复杂删除操作

我不认为级联删除与触发器一样糟糕,因为它们只删除数据,触发器里面可能有各种讨厌的东西。
一般来说,我完全避免真正的删除,而是使用逻辑删除(即,有一个名为isDeleted的位列设置为true)。到目前为止我所看到的总结:

  • 有些人根本不喜欢级联
级联删除
  • 当关系的语义可能涉及排他的“is-part”描述时,级联删除可能有意义。例如,订单行记录是其父订单的一部分,并且订单行永远不会在多个订单之间共享。如果订单消失,订单行也应该消失,没有订单的行将是一个问题
  • Cascade Delete的典型示例是SomeObject和SomeObjectItems,其中items记录在没有相应主记录的情况下存在没有任何意义
  • 如果要保留历史记录或使用“软/逻辑删除”,其中仅将删除的位列设置为1/true,则不应使用级联删除
级联更新
  • 当跨表使用实键而不是代理键(标识/自动增量列)时,级联更新可能有意义
  • 级联更新的典型示例是当您有一个可变的外键时,例如可以更改的用户名
  • 您不应该对标识/自动增量列的键使用级联更新
  • 级联更新最好与唯一约束结合使用
何时使用级联
  • 在允许操作级联之前,您可能希望从用户处获得额外的确认,但这取决于您的应用程序
  • 如果外键设置错误,级联会给您带来麻烦。但如果你做对了,你应该会没事的
  • 在未完全理解级联之前使用级联是不明智的。然而,它是一个有用的特性,因此值得花时间去理解

我和这里的其他人一样,发现级联删除实际上只是略有帮助(在其他表中删除引用的数据实际上没有那么多工作——如果有很多表,您只需使用脚本将其自动化)但当有人意外地级联删除了一些难以恢复的重要数据时,这真的很烦人

我会使用的唯一情况是,如果表中的数据受到高度控制(例如,有限的权限),并且仅更新或删除
 DELETE FROM table WHERE SomeDate < 7 years ago;
 FOR EACH R IN (SELECT FROM table WHERE SomeDate < 7 years ago) LOOP
   DELETE FROM ChildTable WHERE tableId = R.tableId;
   DELETE FROM table WHERE tableId = R.tableid;
   /* More child tables here */
 NEXT
DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'