mysql中On Delete Cascade和On Update Cascade之间的区别


45

我在MySQL数据库中有两个表parentchild。我试图基于父表将外键引用添加到我的子表中。有没有之间的任何显著差异ON UPDATE CASCADEON DELETE CASCADE

我的父母表

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

我的问题是:以下sql查询之间有什么区别。

  1. ON DELETE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON DELETE CASCADE
    ) ENGINE=INNODB;
    
  2. ON UPDATE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON UPDATE CASCADE
    ) ENGINE=INNODB;
    
  3. ON UPDATE CASCADE ON DELETE CASCADE

    CREATE TABLE child (
            id INT, 
            parent_id INT,
            INDEX par_ind (parent_id),
            FOREIGN KEY (parent_id) 
                REFERENCES parent(id)
                ON UPDATE CASCADE ON DELETE CASCADE
        ) ENGINE=INNODB;
    

查询中是否有任何错误?这些查询(1、2和3)是什么意思?他们是一样的吗?


1
ps <nitpick>为完整起见,您在上面谈论的是DDL(数据定义语言)语句,而不是查询。查询通常被认为是DML(数据操纵语言SELECT,插入,更新,删除)</挑剔>
Vérace

出于完整性考虑,我再次想知道另一个ps,我想知道默认值是什么。所以我创建了一个没有更新或删除的孩子。然后发生的事情是,您既不能更新也不能删除具有依赖子项的父项。这非常有意义,但MySQL的并不总是特定特征的:-)模型
Vérace

Answers:


64

关于这个主题的一个很好的线索可以在这里这里找到。有关MySQL的权威指南,当然是文档,可以在这里找到。

在SQL 2003标准中,有5种不同的引用动作:

  1. 级联
  2. 限制
  3. 不采取行动
  4. 设置为空
  5. 默认设置

要回答这个问题:

  1. 级联

    • ON DELETE CASCADE表示如果删除了父记录,那么所有子记录也会被删除。我认为这不是一个好主意。您应该跟踪数据库中曾经存在的所有数据,尽管可以使用TRIGGERs 来完成。(但是,请参阅下面的注释中的警告)。

    • ON UPDATE CASCADE表示如果更改了父主键,则子值也将更改以反映这一点。我再次认为这不是一个好主意。如果您PRIMARY KEY以任何规律性(甚至根本没有!)更改s,那么您的设计就有问题。同样,请参阅评论。

    • ON UPDATE CASCADE ON DELETE CASCADE这意味着,如果你UPDATE DELETE父,改变级联孩子。这相当于AND前两个语句的结果。

  2. 限制

    • RESTRICT表示任何删除和/或更新父项的尝试都将失败并引发错误。如果未明确指定引用动作,这是默认行为。

      对于未指定的ON DELETEON UPDATE,默认操作始终为RESTRICT`。

  3. 不采取行动

    • NO ACTION:从手册。标准SQL中的关键字。在MySQL中,等效于RESTRICT。如果引用表中有相关​​的外键值,则MySQL服务器会拒绝父表的删除或更新操作。某些数据库系统具有延迟检查,并且NO ACTION是延迟检查。在MySQL中,外键约束会立即检查,因此NO ACTION与相同RESTRICT
  4. 设置为空

    • SET NULL-再次来自手册。从父表中删除或更新该行,并将子表中的一个或多个外键列设置为NULL。恕我直言,这不是最好的主意,主要是因为没有“时间遍历”的方法-即回溯子表并将记录与NULLs和相关的父记录相关联- CASCADE或者使用TRIGGERs填充日志记录表以进行跟踪更改(但请参阅评论)。
  5. 默认设置

    • SET DEFAULT。MySQL尚未执行的SQL标准的另一部分(可能非常有用)!允许开发人员指定一个值,以将UPDATE或DELETE上的外键列设置为该值。InnoDB和NDB将拒绝带有SET DEFAULT子句的表定义。

如上所述,您应该花一些时间在此处查看文档。


8
我喜欢您的完整答案,但是我不同意这一说法。“您应该跟踪数据库中曾经存在的所有数据”-这实际上取决于数据库的设计和目的。例如,食谱定义(我不是在谈论食物-更像是系统配置),当食谱定义被删除时,保留该食谱的关联子项是没有意义的-只是无缘无故地肿了数据库。也是机器系统的工作表-我不再需要数据了;处理并摆脱它。除此之外,您的答案很棒。
StixO

2
与@StixO相似,我主要喜欢这个答案,但是我不同意更改主键。在某些设计中,这绝对不是一个好主意,但是当您进入分布式数据库时,非常希望可以自由地重新分配主键而不丢失记录的身份。
加雷特·克拉伯恩(Garet Claborn)

“在我看来,这不是一个好主意。您应该跟踪数据库中曾经存在的所有数据。” -不确定我明白你的意思。如果您级联为“删除时”,那么您已经决定需要删除某些内容。如果您决定从不删除任何内容,则不会层叠。拥有它的好处是,在您的应用程序中,您可以确定当您查找带有外部ID的记录时,便知道该记录将存在,并且如果您决定删除该数据库,将不会有任何孤立的行充斥数据库。的东西。
杰夫·瑞安

这里的逻辑在某些地方是非常错误的,在我们新的GDPR世界中更是如此。我确实同意这样的观点,即如果主键正在更改,则可能表明存在某些错误。
Chuck Le Butt

如果您以任何规律性(甚至根本没有改变)更改PRIMARY KEY,则您的设计有问题。 您是说在UPDATE CASCADE上更改键的值或键的名称吗?
Billal Begueradj

8

当父表上的引用记录更改其ID以及将其删除时,分别执行这两项操作。

如果执行:

UPDATE parent SET id = -1 WHERE id = 1;

而至少有一个记录上childparent_id = 1,1)将失败; 在情况2)和3)中,parent_id = 1的所有记录都将更新为parent_id = -1。

如果执行:

DELETE FROM parent WHERE id = 1;

而至少有一个记录上childparent_id = 1,2)将失败; 在情况1)和3)中,所有带有parent_id = 1的记录都将被删除。

3)在语法上是正确的。

完整的文档可以在手册中找到


6

我没有足够的声誉来评论以前的答案。所以我认为我会详细说明。

1)ON DELETE CASCADE表示如果删除了父记录,那么所有引用的子记录也会被删除。ON UPDATE默认为RESTRICT,这意味着父记录上的UPDATE将失败。

2)ON DELETE操作默认为RESTRICT,这意味着父记录上的DELETE将失败。当父记录更新时,ON UPDATE CASCADE将更新所有引用的子记录。

3)参见上面1)和2)中的CASCADE动作。

关于将父记录ID用作外键(在子表中)-经验表明:a)如果ID是自动生成的序列号,则不要将其用作外键。请改用其他一些唯一的父键。b)如果ID是GUID,则可以将它们用作外键。当您导出和导入记录或将记录复制到另一个数据库时,您将在此建议中看到智慧。当将自动生成的序列号作为外键引用时,要处理它们会很麻烦。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.