1.7.2.3 外键约束差异

外键约束的 MySQL 实现在以下关键方面不同于 SQL 标准:

  • 如果父表中有几行具有相同的引用键值, InnoDB则执行外键检查,就好像其他具有相同键值的父行不存在一样。例如,如果您定义了一个 RESTRICT类型约束,并且有一个带有多个父行的子行, InnoDB则不允许删除任何父行。

  • 如果ON UPDATE CASCADEON UPDATE SET NULL递归更新它之前在同一个级联期间更新过的 同一个表,它的行为就像 RESTRICT. 这意味着您不能使用自引用ON UPDATE CASCADEON UPDATE SET NULL操作。这是为了防止级联更新导致的无限循环。ON DELETE SET NULL另一方面,自我参照是可能的,就像自我参照一样ON DELETE CASCADE。级联操作的嵌套深度不得超过 15 层。

  • 在插入、删除或更新多行的 SQL 语句中,逐行检查外键约束(如唯一约束)。执行外键检查时,InnoDB在必须检查的子记录或父记录上设置共享行级锁。MySQL 立即检查外键约束;检查不会延迟到事务提交。根据 SQL 标准,默认行为应该是延迟检查。也就是说,只有在处理完整个 SQL 语句后才会检查约束。这意味着无法删除使用外键引用自身的行。

  • 没有存储引擎(包括InnoDB)识别或强制MATCH引用完整性约束定义中使用的子句。使用显式MATCH子句不会产生指定的效果,它会导致ON DELETEandON UPDATE子句被忽略。MATCH 应避免 指定。

    SQL 标准中的MATCH子句控制NULL在与引用表中的主键进行比较时如何处理复合(多列)外键中的值。MySQL 实质上实现了由 定义的语义 MATCH SIMPLE,它允许外键全部或部分为NULL。在这种情况下,可以插入包含此类外键的(子表)行,即使它与引用的(父)表中的任何行都不匹配。(可以使用触发器实现其他语义。)

  • 出于性能原因,MySQL 要求对引用的列进行索引。但是,MySQL 不强制要求声明引用的 UNIQUENOT NULL

    引用非键的FOREIGN KEY约束UNIQUE不是标准 SQL,而是 InnoDB扩展。NDB另一方面,存储引擎需要在任何引用为外键的列上有一个明确的唯一键(或主键) 。

    对非唯一键或包含值的键的外键引用的处理对于 or等NULL​​操作没有明确定义 。建议您使用仅引用(包括 )和键的外键。 UPDATEDELETE CASCADEUNIQUEPRIMARYNOT NULL

  • 对于不支持外键的存储引擎(如MyISAM),MySQL Server 会解析并忽略外键规范。

  • MySQL 解析但忽略内联 REFERENCES规范(如 SQL 标准中所定义),其中引用被定义为列规范的一部分。MySQL REFERENCES仅在指定为单独FOREIGN KEY 规范的一部分时才接受子句。

    定义一个列以使用一个 子句没有实际效果,只是作为一个备忘录或注释给你,你当前定义的列是为了引用另一个表中的列。使用此语法时务必要意识到: REFERENCES tbl_name(col_name)

    • MySQL 不执行任何类型的检查以确保col_name实际存在于tbl_name(或什至tbl_name本身存在)。

    • MySQL 不会执行任何类型的操作, tbl_name例如删除行以响应对您正在定义的表中的行执行的操作;换句话说,此语法不会导致任何ON DELETE行为ON UPDATE。(尽管您可以将ON DELETEor ON UPDATE子句写为子句的一部分 REFERENCES,但它也会被忽略。)

    • 此语法创建一个;它不会创建任何类型的索引或键。

    您可以使用这样创建的列作为连接列,如下所示:

    CREATE TABLE person (
        id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
        name CHAR(60) NOT NULL,
        PRIMARY KEY (id)
    );
    
    CREATE TABLE shirt (
        id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
        style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
        color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
        owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
        PRIMARY KEY (id)
    );
    
    INSERT INTO person VALUES (NULL, 'Antonio Paz');
    
    SELECT @last := LAST_INSERT_ID();
    
    INSERT INTO shirt VALUES
    (NULL, 'polo', 'blue', @last),
    (NULL, 'dress', 'white', @last),
    (NULL, 't-shirt', 'blue', @last);
    
    INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');
    
    SELECT @last := LAST_INSERT_ID();
    
    INSERT INTO shirt VALUES
    (NULL, 'dress', 'orange', @last),
    (NULL, 'polo', 'red', @last),
    (NULL, 'dress', 'blue', @last),
    (NULL, 't-shirt', 'white', @last);
    
    SELECT * FROM person;
    +----+---------------------+
    | id | name                |
    +----+---------------------+
    |  1 | Antonio Paz         |
    |  2 | Lilliana Angelovska |
    +----+---------------------+
    
    SELECT * FROM shirt;
    +----+---------+--------+-------+
    | id | style   | color  | owner |
    +----+---------+--------+-------+
    |  1 | polo    | blue   |     1 |
    |  2 | dress   | white  |     1 |
    |  3 | t-shirt | blue   |     1 |
    |  4 | dress   | orange |     2 |
    |  5 | polo    | red    |     2 |
    |  6 | dress   | blue   |     2 |
    |  7 | t-shirt | white  |     2 |
    +----+---------+--------+-------+
    
    
    SELECT s.* FROM person p INNER JOIN shirt s
       ON s.owner = p.id
     WHERE p.name LIKE 'Lilliana%'
       AND s.color <> 'white';
    
    +----+-------+--------+-------+
    | id | style | color  | owner |
    +----+-------+--------+-------+
    |  4 | dress | orange |     2 |
    |  5 | polo  | red    |     2 |
    |  6 | dress | blue   |     2 |
    +----+-------+--------+-------+

    以这种方式使用时,该 REFERENCES子句不会显示在SHOW CREATE TABLEor 的输出中DESCRIBE

    SHOW CREATE TABLE shirt\G
    *************************** 1. row ***************************
    Table: shirt
    Create Table: CREATE TABLE `shirt` (
    `id` smallint(5) unsigned NOT NULL auto_increment,
    `style` enum('t-shirt','polo','dress') NOT NULL,
    `color` enum('red','blue','orange','white','black') NOT NULL,
    `owner` smallint(5) unsigned NOT NULL,
    PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1

有关外键约束的信息,请参阅 第 13.1.18.5 节,“外键约束”