18

在 SQL Server 2005 中,我刚刚发现了臭名昭著的错误消息:

在 YYY 表上引入 FOREIGN KEY 约束 XXX 可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

现在,StackOverflow 有几个关于此错误消息的主题,所以我已经有了解决方案(在我的情况下,我将不得不使用触发器),但我很好奇为什么会出现这样的问题。

据我了解,他们基本上想要避免两种情况——循环和多条路径。循环将是两个表具有彼此级联的外键。好的,一个循环也可以跨越多个表,但这是基本情况,更容易分析。

当 TableA 具有 TableB 和 TableC 的外键,而 TableB 也具有 TableC 的外键时,就会出现多条路径。再次 - 这是最小的基本情况。

我看不到在任何这些表中删除或更新记录时会出现任何问题。当然,您可能需要多次查询同一个表以查看哪些记录需要更新/删除,但这真的有问题吗?这是性能问题吗?

在其他 SO 主题中,人们甚至将使用级联标记为“有风险的”,并指出“解决级联路径是一个复杂的问题”。为什么?风险在哪里?哪里有问题?

4

6 回答 6

4

您有一个子表,其中包含来自同一父级的 2 个级联路径:一个“删除”,一个“空”。

什么优先?之后你期待什么?ETC

注意:触发器是代码,可以为级联添加一些智能或条件。

于 2009-10-31T19:25:12.153 回答
2

我们禁止使用级联删除的原因与性能和锁定有关。是的,删除一条记录并没有那么糟糕,但迟早您将需要删除一大组记录,您的数据库将陷入停顿。

如果您要删除足够多的记录,SQL Server 可能会升级为表锁定,并且在完成之前没有人可以对表执行任何操作。

我们最近将我们的一位客户移到了他自己的服务器上。作为交易的一部分,我们还必须从原始服务器中删除该客户的所有记录。批量删除他的所有信息(以免引起其他用户的问题)花了几个月的时间。如果我们设置了级联删除,那么其他客户端将在很长一段时间内无法访问数据库,因为在一个事务中删除了数百万条记录,并且在事务完成之前数百个表被锁定。

我还可以看到在使用级联删除时可能发生死锁的场景,因为我们无法控制级联路径的顺序,并且我们的数据库有些非规范化,客户端 ID 出现在大多数表中。因此,如果它将具有外键的一个表也锁定到第三个表以及位于不同路径中的客户端表,它可能无法检查该表以便从第三个表中删除,因为这就是全部一个事务,并且在完成之前不会释放锁。因此,如果它看到在事务中创建死锁的可能性,它可能不会让我们设置级联删除。

避免级联删除的另一个原因是,有时子记录的存在足以成为不删除父记录的理由。例如,如果您有一个客户表并且该客户过去曾有过订单,您不希望删除他并丢失有关实际订单的信息。

于 2009-10-28T15:32:28.250 回答
1

考虑一张员工表:

CREATE TABLE Employee
(
    EmpID   INTEGER NOT NULL PRIMARY KEY,
    Name    VARCHAR(40) NOT NULL,
    MgrID   INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE
);

INSERT INTO Employees(     1, "Bill",   1);
INSERT INTO Employees(    23, "Steve",  1);
INSERT INTO Employees(234212, "Helen", 23);

现在假设比尔退休:

DELETE FROM Employees WHERE Name = "Bill";

哎呀!每个人都被解雇了!

[我们可以辩论语法的细节是否正确;我认为这个概念是成立的。]

于 2009-10-30T05:16:39.897 回答
1

我认为问题在于,当您将一条路径设为“ON DELETE CASCADE”而另一条路径设为“ON DELETE RESTRICT”或“NO ACTION”时,结果(结果)是不可预测的。这取决于哪个删除触发器(这也是一个触发器,但您不必自己构建)将首先执行。

于 2013-11-14T11:24:08.957 回答
0

我同意级联是“有风险的”,应该避免。(我个人更喜欢手动级联更改,而不是让 sql server 自动处理它们)。这也是因为即使 sql server 删除了数百万行,输出仍然会显示为

(1 行受影响)

于 2009-10-28T15:04:25.167 回答
-1

我认为是否使用 ON DELETE CASCADE 选项是您正在实施的业务模型的问题。两个业务对象之间的关系可以是简单的“关联”,其中关系的两端都是相关的,但也可以是独立的对象,其生命周期不同并由其他逻辑控制。然而,也存在“聚合”关系,其中一个对象实际上可能被视为“子”或“详细”对象的“父”或“所有者”。还有一个更强大的“组合”关系概念,其中一个对象仅作为多个部分的组合存在。在“关联”情况下,您通常不会声明 ON DELETE CASCADE 约束。然而,对于聚合或组合,ON DELETE CASCADE 可帮助您以声明性方式更准确地将业务模型映射到数据库。这就是为什么 MS SQL Server 将此选项的使用限制为单个级联路径让我很恼火的原因。如果我没记错的话,许多其他广泛使用的 SQL 数据库系统并没有施加这样的限制。

于 2010-10-27T07:21:48.983 回答