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

Lon*_*olf 85 mysql innodb foreign-key mysql-5.5

我在 MySQL 数据库中有两个表 - parent, child. 我正在尝试根据父表向我的子表添加外键引用。有没有之间的任何显著差异ON UPDATE CASCADEON DELETE CASCADE

我的父表

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;
Run Code Online (Sandbox Code Playgroud)

我的问题是:以下 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;
    
    Run Code Online (Sandbox Code Playgroud)
  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;
    
    Run Code Online (Sandbox Code Playgroud)
  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;
    
    Run Code Online (Sandbox Code Playgroud)

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

Vér*_*ace 117

关于这个主题的一个很好的线索可以在这里这里找到。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父级,更改将级联到子级。这相当于ANDing 前两个语句的结果。

  2. 严格

    • RESTRICT意味着任何删除和/或更新父项的尝试都将失败并抛出错误。这是未明确指定引用操作时的默认行为。

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

  3. 没有行动

    • NO ACTION: 从手册。来自标准 SQL 的关键字。在 MySQL 中,相当于RESTRICT. 如果引用的表中存在相关的外键值,MySQL Server 将拒绝对父表的删除或更新操作。有些数据库系统有延迟检查,并且NO ACTION是延迟检查。在 MySQL 中,会立即检查外键约束,因此NO ACTIONRESTRICT.
  4. 置空

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

    • SET DEFAULT. SQL 标准的另一个(可能非常有用)部分是 MySQL 没有费心实现的!允许开发人员指定一个值,用于在 UPDATE 或 DELETE 中设置外键列。InnoDB 和 NDB 将拒绝带有SET DEFAULT子句的表定义。

如上所述,您应该花一些时间查看文档,这里

  • 我喜欢你完整的回答,但我不同意这个说法。“您应该跟踪数据库中曾经存在的所有数据”——这实际上取决于数据库的设计和目的。例如,食谱定义(我不是在谈论食物 - 更像是系统配置)当食谱定义被删除时,保留该食谱的相关子项是没有意义的 - 这只会无缘无故地膨胀数据库。还有机器系统的工作表 - 我不再需要数据了;处理并摆脱它。除此之外,您的回答很棒。 (16认同)
  • 类似于@StixO,我最喜欢这个答案,但我不同意更改主键。肯定有一些设计,这将是一个坏主意,但是当您进入分布式数据库时,非常希望可以自由地重新分配主键而不会丢失记录的身份。 (3认同)

jyn*_*nus 9

这两个是分别在父表上的引用记录更改其 id 和删除时要执行的操作。

如果执行:

UPDATE parent SET id = -1 WHERE id = 1;
Run Code Online (Sandbox Code Playgroud)

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

如果执行:

DELETE FROM parent WHERE id = 1;
Run Code Online (Sandbox Code Playgroud)

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

3) 语法正确。

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

  • 定义 1,2,3 而不是依赖于从未被编辑的问题会更好地提供答案。 (2认同)

小智 7

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

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,那么可以将它们用作外键。当您导出和导入记录或将记录复制到另一个数据库时,您将看到此建议的智慧。数据迁移过程中自动生成的序列号作为外键引用时,处理起来太麻烦了。