为什么 MySQL 没有正确命名我的外键?
Why is MySQL not properly naming my foreign key?
请考虑以下 SQL 我 运行 在 MySQL 8.0.22 中(在 InnoDB 数据库中)的代码:
CREATE TABLE `person` (
`person_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
PRIMARY KEY (`person_id`)
);
CREATE TABLE `pet` (
`pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
PRIMARY KEY (`pet_id`)
);
ALTER TABLE `pet`
ADD COLUMN `owner_id` smallint unsigned;
ALTER TABLE `pet`
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY `idx_fk_pet_person` (`owner_id`)
REFERENCES `person` (`person_id`);
SHOW CREATE TABLE pet;
SHOW CREATE TABLE pet
的输出是:
CREATE TABLE `pet` (
`pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`owner_id` smallint unsigned DEFAULT NULL,
PRIMARY KEY (`pet_id`),
KEY `fk_pet_person` (`owner_id`),
CONSTRAINT `fk_pet_person` FOREIGN KEY (`owner_id`) REFERENCES `person` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
在上面的输出中,当我在 ALTER TABLE
命令中将其名称指定为 idx_fk_pet_person
时,为什么 KEY 的名称为 fk_pet_person
?我怎样才能让它这样命名?
您混淆了 FOREIGN KEY 和使其起作用的 INDEX。请注意 - 在您的代码中显示的约束定义中没有表达式名称(看起来像索引定义但不是)。
当约束没有合适的索引时,则自动创建该索引,并使用约束名作为索引名。如果存在合适的索引,则不会自动创建。
如果您希望索引具有已定义的名称,那么您必须在创建约束之前在单独的 ALTER TABLE
(子)语句中创建此索引:
ALTER TABLE `pet`
ADD KEY `idx_fk_pet_person` (`owner_id`),
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY (`owner_id`)
REFERENCES `person` (`person_id`);
或
ALTER TABLE `pet`
ADD KEY `idx_fk_pet_person` (`owner_id`);
ALTER TABLE `pet`
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY (`owner_id`)
REFERENCES `person` (`person_id`);
MySQL 文档指定了创建外键的语法:
[CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (col_name, ...)
REFERENCES tbl_name (col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
我的代码没有设置 [index_name]
而是索引名称自动与约束名称相同的原因有两个。从摘自 MySQL 8.0 参考手册第 13.1.20.5 FOREIGN KEY Constraints:
的这段中可以明显看出两者
Prior to MySQL 8.0.16, if the CONSTRAINT symbol clause was not defined, or a symbol was not included following the CONSTRAINT keyword, both InnoDB and NDB storage engines would use the FOREIGN_KEY index_name if defined. In MySQL 8.0.16 and higher, the FOREIGN_KEY index_name is ignored.
第一个原因是我运行代码在MySQL8.0.22.
第二个原因是我应该省略约束名称。
@akina 的回答中的解决方法确实使我能够为外键(索引)指定一个不同于约束名称的名称。
请考虑以下 SQL 我 运行 在 MySQL 8.0.22 中(在 InnoDB 数据库中)的代码:
CREATE TABLE `person` (
`person_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
PRIMARY KEY (`person_id`)
);
CREATE TABLE `pet` (
`pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
PRIMARY KEY (`pet_id`)
);
ALTER TABLE `pet`
ADD COLUMN `owner_id` smallint unsigned;
ALTER TABLE `pet`
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY `idx_fk_pet_person` (`owner_id`)
REFERENCES `person` (`person_id`);
SHOW CREATE TABLE pet;
SHOW CREATE TABLE pet
的输出是:
CREATE TABLE `pet` (
`pet_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`owner_id` smallint unsigned DEFAULT NULL,
PRIMARY KEY (`pet_id`),
KEY `fk_pet_person` (`owner_id`),
CONSTRAINT `fk_pet_person` FOREIGN KEY (`owner_id`) REFERENCES `person` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
在上面的输出中,当我在 ALTER TABLE
命令中将其名称指定为 idx_fk_pet_person
时,为什么 KEY 的名称为 fk_pet_person
?我怎样才能让它这样命名?
您混淆了 FOREIGN KEY 和使其起作用的 INDEX。请注意 - 在您的代码中显示的约束定义中没有表达式名称(看起来像索引定义但不是)。
当约束没有合适的索引时,则自动创建该索引,并使用约束名作为索引名。如果存在合适的索引,则不会自动创建。
如果您希望索引具有已定义的名称,那么您必须在创建约束之前在单独的 ALTER TABLE
(子)语句中创建此索引:
ALTER TABLE `pet`
ADD KEY `idx_fk_pet_person` (`owner_id`),
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY (`owner_id`)
REFERENCES `person` (`person_id`);
或
ALTER TABLE `pet`
ADD KEY `idx_fk_pet_person` (`owner_id`);
ALTER TABLE `pet`
ADD CONSTRAINT `fk_pet_person`
FOREIGN KEY (`owner_id`)
REFERENCES `person` (`person_id`);
MySQL 文档指定了创建外键的语法:
[CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (col_name, ...)
REFERENCES tbl_name (col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
我的代码没有设置 [index_name]
而是索引名称自动与约束名称相同的原因有两个。从摘自 MySQL 8.0 参考手册第 13.1.20.5 FOREIGN KEY Constraints:
Prior to MySQL 8.0.16, if the CONSTRAINT symbol clause was not defined, or a symbol was not included following the CONSTRAINT keyword, both InnoDB and NDB storage engines would use the FOREIGN_KEY index_name if defined. In MySQL 8.0.16 and higher, the FOREIGN_KEY index_name is ignored.
第一个原因是我运行代码在MySQL8.0.22.
第二个原因是我应该省略约束名称。
@akina 的回答中的解决方法确实使我能够为外键(索引)指定一个不同于约束名称的名称。