#### 1.7.2.3 外键约束差异

[](<>)[](<>)

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

-   如果父表中有几行具有相同的引用键值，[`InnoDB`](innodb-storage-engine.html)执行外键检查，就好像具有相同键值的其他父行不存在一样。例如，如果您定义一个`严格`类型约束，并且有一个带有多个父行的子行，`InnoDB`不允许删除任何父行。

-   如果`更新级联`要么`更新设置为空`递归更新*同桌*它以前在同一个级联中更新过，它的行为就像`严格`.这意味着您不能使用自引用`更新级联`要么`更新设置为空`操作。这是为了防止级联更新导致的无限循环。自我参照`删除设置为空`, 另一方面, 是可能的, 就像自引用一样`删除级联`.级联操作的嵌套深度不得超过 15 层。

-   在插入、删除或更新许多行的 SQL 语句中，外键约束（如唯一约束）是逐行检查的。在执行外键检查时，[`InnoDB`](innodb-storage-engine.html)在必须检查的子记录或父记录上设置共享行级锁。MySQL 立即检查外键约束；检查不推迟到事务提交。根据 SQL 标准，默认行为应该是延迟检查。也就是说，约束仅在*整个 SQL 语句*已处理。这意味着无法删除使用外键引用自身的行。

-   没有存储引擎，包括`InnoDB`, 承认或执行`匹配`引用完整性约束定义中使用的子句。使用显式`匹配`子句没有指定的效果，它会导致`删除时`和`在更新`要忽略的条款。指定`匹配`应该避免。

    这`匹配`SQL 标准中的子句控制如何`空值`与引用表中的主键进行比较时，会处理复合（多列）外键中的值。MySQL本质上实现了定义的语义`匹配简单`，它允许外键是全部或部分`空值`.在这种情况下，可以插入包含此类外键的（子表）行，即使它与引用（父）表中的任何行都不匹配。（可以使用触发器实现其他语义。）

-   出于性能原因，MySQL 要求对引用的列进行索引。但是，MySQL 不强制要求引用的列是`独特`或被宣布`非空`.

    一种`外键`引用非的约束`独特`key 不是标准 SQL，而是[`InnoDB`](innodb-storage-engine.html)延期。这[`新开发银行`](mysql-cluster.html)另一方面，存储引擎需要在任何被引用为外键的列上都有一个明确的唯一键（或主键）。

    处理对非唯一键或包含的键的外键引用`空值`值没有很好地定义为操作，如[`更新`](update.html)要么`删除级联`.建议您使用仅引用的外键`独特`（包含`基本的`） 和`非空`键。

-   对于不支持外键的存储引擎（如[`MyISAM`](myisam-storage-engine.html))，MySQL 服务器解析并忽略外键规范。

-   MySQL 解析但忽略“内联`参考`规范”（在 SQL 标准中定义），其中引用被定义为列规范的一部分。MySQL 接受`参考`子句仅在指定为单独的一部分时`外键`规格。

    定义要使用的列`参考 *`tbl_name`*(*`col_name`*)`条款没有实际效力并且*仅作为对您的备注或评论，您当前定义的列旨在引用另一个表中的列*.使用此语法时，重要的是要意识到：

    -   MySQL 不执行任何类型的检查以确保*`col_name`*实际上存在于*`tbl_name`*（甚至那个*`tbl_name`*本身存在）。

    -   MySQL 不执行任何类型的操作*`tbl_name`*例如删除行以响应对您正在定义的表中的行采取的操作；换句话说，这种语法不会导致`删除时`要么`在更新`任何行为。（虽然你可以写一个`删除时`要么`在更新`作为条款的一部分`参考`子句，它也被忽略。）

    -   此语法创建一个*柱子*;它确实**不是**创建任何类型的索引或键。

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

        ```
        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 |
        +----+-------+--------+-------+
        ```

        当以这种方式使用时，`参考`子句不显示在输出中[`显示创建表`](show-create-table.html)要么[`描述`](describe.html)：

        ```
        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=utf8mb4
        ```

    有关外键约束的信息，请参阅[第 13.1.20.5 节，“外键约束”](create-table-foreign-keys.html).
