外键约束的 MySQL 实现在以下关键方面不同于 SQL 标准:
如果父表中有几行具有相同的引用键值,
InnoDB
则执行外键检查,就好像其他具有相同键值的父行不存在一样。例如,如果您定义了一个RESTRICT
类型约束,并且有一个带有多个父行的子行,InnoDB
则不允许删除任何父行。如果
ON UPDATE CASCADE
或ON UPDATE SET NULL
递归更新它之前在同一个级联期间更新过的 同一个表,它的行为就像RESTRICT
. 这意味着您不能使用自引用ON UPDATE CASCADE
或ON UPDATE SET NULL
操作。这是为了防止级联更新导致的无限循环。ON DELETE SET NULL
另一方面,自我参照是可能的,就像自我参照一样ON DELETE CASCADE
。级联操作的嵌套深度不得超过 15 层。在插入、删除或更新多行的 SQL 语句中,逐行检查外键约束(如唯一约束)。执行外键检查时,
InnoDB
在必须检查的子记录或父记录上设置共享行级锁。MySQL 立即检查外键约束;检查不会延迟到事务提交。根据 SQL 标准,默认行为应该是延迟检查。也就是说,只有在处理完整个 SQL 语句后才会检查约束。这意味着无法删除使用外键引用自身的行。没有存储引擎(包括
InnoDB
)识别或强制MATCH
引用完整性约束定义中使用的子句。使用显式MATCH
子句不会产生指定的效果,它会导致ON DELETE
andON UPDATE
子句被忽略。MATCH
应避免 指定。SQL 标准中的
MATCH
子句控制NULL
在与引用表中的主键进行比较时如何处理复合(多列)外键中的值。MySQL 实质上实现了由 定义的语义MATCH SIMPLE
,它允许外键全部或部分为NULL
。在这种情况下,可以插入包含此类外键的(子表)行,即使它与引用的(父)表中的任何行都不匹配。(可以使用触发器实现其他语义。)出于性能原因,MySQL 要求对引用的列进行索引。但是,MySQL 不强制要求声明引用的
UNIQUE
列NOT NULL
。引用非键的
FOREIGN KEY
约束UNIQUE
不是标准 SQL,而是InnoDB
扩展。NDB
另一方面,存储引擎需要在任何引用为外键的列上有一个明确的唯一键(或主键) 。对非唯一键或包含值的键的外键引用的处理对于 or等
NULL
操作没有明确定义 。建议您使用仅引用(包括 )和键的外键。UPDATE
DELETE CASCADE
UNIQUE
PRIMARY
NOT NULL
对于不支持外键的存储引擎(如
MyISAM
),MySQL Server 会解析并忽略外键规范。MySQL 解析但忽略“内联
REFERENCES
规范”(如 SQL 标准中所定义),其中引用被定义为列规范的一部分。MySQLREFERENCES
仅在指定为单独FOREIGN KEY
规范的一部分时才接受子句。定义一个列以使用一个 子句没有实际效果,只是作为一个备忘录或注释给你,你当前定义的列是为了引用另一个表中的列。使用此语法时务必要意识到:
REFERENCES
tbl_name
(col_name
)MySQL 不执行任何类型的检查以确保
col_name
实际存在于tbl_name
(或什至tbl_name
本身存在)。MySQL 不会执行任何类型的操作,
tbl_name
例如删除行以响应对您正在定义的表中的行执行的操作;换句话说,此语法不会导致任何ON DELETE
行为ON UPDATE
。(尽管您可以将ON DELETE
orON 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 TABLE
or 的输出中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=utf8mb4
有关外键约束的信息,请参阅 第 13.1.20.5 节,“外键约束”。