# 1.7.2.3 外键约束差异

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

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

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

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

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

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

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

    一种外键引用非的约束独特key 不是标准 SQL,而是InnoDB延期。这新开发银行另一方面,存储引擎需要在任何被引用为外键的列上都有一个明确的唯一键(或主键)。

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

  • 对于不支持外键的存储引擎(如MyISAM),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 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 节,“外键约束”.