Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL不一致地更改与InnoDB表上的外键关联的索引的名称_Mysql_Sql_Indexing_Foreign Keys_Innodb - Fatal编程技术网

MySQL不一致地更改与InnoDB表上的外键关联的索引的名称

MySQL不一致地更改与InnoDB表上的外键关联的索引的名称,mysql,sql,indexing,foreign-keys,innodb,Mysql,Sql,Indexing,Foreign Keys,Innodb,在删除和添加外键时,altertable语句的行为方式似乎不一致。有时关联的索引将被重命名,有时则不会。我已经确定了发生这种情况的情况: 方法#1 一个简单的person表,具有自动递增的主键id和一个自身self\u id的外键列。注意:两个单独的表的行为相同,我使用了一个表来简化示例 CREATE TABLE `person` ( `id` int(11) NOT NULL AUTO_INCREMENT, `self_id` int(11) DEFAULT NULL, PRIM

在删除和添加外键时,
altertable
语句的行为方式似乎不一致。有时关联的索引将被重命名,有时则不会。我已经确定了发生这种情况的情况:


方法#1

一个简单的
person
表,具有自动递增的主键
id
和一个自身
self\u id
的外键列。注意:两个单独的表的行为相同,我使用了一个表来简化示例

CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `self_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `self_id_fk` (`self_id`),
  CONSTRAINT `self_id_fk` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
接下来,我通过删除现有的外键,然后添加一个新的外键来重命名外键。这是在单个语句中完成的,但如果拆分为多个
altertable
语句,则行为相同

ALTER TABLE `person`
  DROP FOREIGN KEY `self_id_fk`,
  ADD CONSTRAINT `a_new_fk_name` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`);
本声明后的表格如下:

CREATE TABLE `person` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `self_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `self_id_fk` (`self_id`),
  CONSTRAINT `a_new_fk_name` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
请注意,外键已重命名,但索引尚未重命名


方法#2

另一种方法是首先创建不带任何外键或索引的表:

CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `self_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
接下来添加外键约束:

ALTER TABLE `person` ADD CONSTRAINT `self_id_fk` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`);
结果如下表所示:

CREATE TABLE `person` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `self_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `self_id_fk` (`self_id`),
  CONSTRAINT `self_id_fk` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
请注意,索引是根据行为自动创建的

。。。在引用表上自动创建索引,如果 不存在

接下来,我以与方法1相同的方式重命名外键:

ALTER TABLE `person`
  DROP FOREIGN KEY `self_id_fk`,
  ADD CONSTRAINT `a_new_fk_name` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`);
但这次外键和索引都被重命名:

CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `self_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a_new_fk_name` (`self_id`),
  CONSTRAINT `a_new_fk_name` FOREIGN KEY (`self_id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
对发生的事情有什么解释吗?就好像MySQL正在跟踪哪些索引是“自动创建的”,然后在外键更改时重命名它们。在运行
altertable
语句之前,这两种方法的表DDL是相同的,因此MySQL必须跟踪某些“内部引擎状态”


仅从DDL来看,无法预测运行
altertable
语句时MySQL的行为方式。这意味着,一旦一个简单的
altertable
语句运行,两个“模式相同”的数据库可能会以不匹配的模式结束。

我注意到了同样的事情,但我从未见过任何官方文档解释这一点

我同意InnoDB似乎“知道”哪些索引是隐式创建的,哪些是显式创建的。但我不知道它在哪里追踪这些信息。InnoDB在
INFORMATION\u SCHEMA
表中公开了大量元数据,但它必须在内部数据字典中存储更多信息

这是MySQL 5.7及更早版本中关于内部DD的唯一文档:

我唯一的建议是,如果需要可预测的索引名,则需要显式创建索引,然后创建外键约束。不要依赖外键隐式创建索引


MySQL 8.0完全重新设计了数据字典,因此您观察到的行为可能会再次改变

如果您使用
添加外键
,以便MySQL生成外键名称(例如
table_ibfk_1
),事情可能会变得更加混乱-稍后添加命名外键似乎会导致重命名隐式索引以匹配新外键,即使以前的外键仍然存在!您可以使用
altertableaddindex
将隐式索引转换为显式索引。如果添加与现有隐式索引具有相同名称和列的显式索引,则不会出现“重复键名”错误。