在SQL Server中设置外键时,在什么情况下应该在删除或更新时级联它,其背后的原因是什么?
这可能也适用于其他数据库。
我正在寻找每种情况的具体示例,最好是从成功使用它们的人那里获得。
在SQL Server中设置外键时,在什么情况下应该在删除或更新时级联它,其背后的原因是什么?
这可能也适用于其他数据库。
我正在寻找每种情况的具体示例,最好是从成功使用它们的人那里获得。
Answers:
到目前为止我所看到的摘要:
外键是确保数据库引用完整性的最佳方法。避免由于魔术而导致的级联就像在汇编中编写所有内容一样,因为您不相信编译器背后的魔术。
不好的是外键的错误使用,例如,向后创建外键。
胡安·曼努埃尔(Juan Manuel)的例子就是规范的例子,如果您使用代码,那么有更多的机会在数据库中留下伪造的DocumentItems来咬您。
级联更新非常有用,例如,当您通过可以更改的内容引用数据时,例如,用户表的主键是名称,姓氏组合。然后,您希望该组合中的更改传播到引用的任何位置。
@Aidan,您所指的这种清晰度付出了高昂的代价,这是将假数据留在数据库中的机会,这是不小的机会。对我来说,通常只是缺乏对DB的熟悉,并且在与DB合作之前无法找到哪些FK会加剧这种恐惧。要么,要么是不断地滥用级联,在实体在概念上不相关的地方,或者必须保留历史的地方使用级联。
我从不使用级联删除。
如果我想从数据库中删除某些内容,我想明确地告诉数据库我要取出的内容。
当然,它们是数据库中可用的功能,有时可能可以使用它们,例如,如果您有一个“ order”表和一个“ orderItem”表,则您可能希望在删除某个表时清除它们。订购。
我喜欢从代码(或存储过程)中完成代码而获得的清晰度,而不是发生“魔术”事件。
出于同样的原因,我也不喜欢触发器。
需要注意的是,即使您删除了一个“订单”,即使级联删除删除了50个“ orderItem”,您也将得到“ 1行受影响”的报告。
我经常进行级联删除。
知道有人对数据库进行操作可能永远都不会留下任何不需要的数据,这真是一件好事。如果依赖性增加,我只需在Management Studio中更改图表中的约束即可,而不必调整sp或dataacces。
就是说,关于级联删除和循环引用,我有1个问题。这通常会导致数据库中没有级联删除的部分。
我做了很多数据库工作,很少发现级联删除有用。我曾经有效地使用过它们的一次是在报表数据库中,该数据库由每夜的工作进行更新。通过删除自上次导入以来已更改的所有顶级记录,然后重新导入已修改的记录以及与它们相关的任何内容,我可以确保正确导入任何已更改的数据。它使我不必编写从数据库底部到顶部的许多复杂删除操作。
我不认为级联删除像触发器一样糟糕,因为它们仅删除数据,触发器内部可能包含各种讨厌的东西。
通常,我完全避免使用真正的Delete方法,而是使用逻辑删除方法(例如,将名为isDeleted的位列设置为true)。
我听说过DBA和/或“公司策略”完全是由于过去的不良经验而禁止使用“ On Delete Cascade”(及其他)。在一个案例中,一个人写了三个触发器,最终互相呼唤。三天的恢复导致完全禁止扳机,这都是由于一个同志的行动。
当然,有时需要触发器而不是“ On Delete Cascade”,例如需要保留一些子数据时。但是在其他情况下,使用“删除时”级联方法完全有效。“删除级联”的主要优点是它可以捕获所有子级。如果编写的自定义触发器/存储过程编码不正确,则可能不会。
我认为应该允许开发人员根据开发内容和规格说明做出决定。基于不良经历的地毯禁令不应作为标准;“从不使用”的思维过程充其量是严酷的。每次都需要做出判断,并且随着业务模型的变化而进行更改。
这不是发展的全部内容吗?
进行级联删除(而不是在代码中进行删除)的一个原因是提高性能。
情况1:使用级联删除
DELETE FROM table WHERE SomeDate < 7 years ago;
情况2:没有级联删除
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
其次,当您添加带有级联删除的额外子表时,情况1中的代码将继续工作。
我只会在关系的语义是“一部分”的情况下放一个层叠。否则,某些白痴在执行以下操作时将删除数据库的一半:
DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'
可以通过以下三种方式之一来处理对S的删除或更新,以删除在R的某些元组中找到的外键值:
传播称为级联。
有两种情况:
‣如果删除了S中的元组,请删除引用它的R元组。
‣如果更新了S中的元组,请更新引用它的R元组中的值。
如果您正在使用具有不同版本的许多不同模块的系统,则如果级联删除的项目是PK持有者的一部分/拥有的,这将非常有帮助。否则,所有模块在删除PK所有者之前都需要立即打补丁以清理其依赖项,否则,如果未正确执行清理,则将完全省略外键关系,这可能会在系统中留下大量垃圾。
在不鼓励层叠删除一段时间后,我刚刚为两个已经存在的表之间的新交集表(仅要删除的交集)引入了级联删除。如果数据丢失,也还不错。
但是,对于像枚举一样的列表表来说,这是一件坏事:有人从表“ colors”中删除条目13-黄色,并且删除了数据库中的所有黄色项。此外,有时这些内容会以全部删除全部插入的方式进行更新,从而导致完全省略了参照完整性。当然,这是错误的,但是您将如何更改已经运行多年的复杂软件,而引入真正的参照完整性却会带来意料之外的副作用?
另一个问题是,即使删除了主键后仍应保留原始外键值。可以为原始FK创建一个逻辑删除列和一个ON DELETE SET NULL选项,但这又需要触发器或特定的代码来维护冗余(PK删除后除外)键值。
当在物理数据库中实现逻辑超类型和子类型实体时,级联删除非常有用。
当使用单独的超类型和子类型表物理地实现超类型/子类型时(与将所有子类型属性汇总到单个物理超类型表中相反),这些表和问题之间的一种关系就变成了如何使这些表之间的主键100%保持同步。
级联删除对于以下操作而言可能是非常有用的工具:
1)确保删除超类型记录也删除了相应的单个子类型记录。
2)确保对子类型记录的任何删除也会删除超类型记录。这是通过在子类型表上实现“代替”删除触发器来实现的,该触发器将删除相应的超级类型记录,然后删除该超级类型记录,然后依次删除该子类型记录。
以这种方式使用级联删除操作可以确保不存在任何孤立的超类型记录或子类型记录,而不管您是先删除超类型记录还是先删除子类型记录。
sql-server
标签,对社区会更有用。