mysql 8 (innodb) 新创建索引的外键约束
mysql 8 (innodb) foreign key constraints on newly created indexes
假设我有一个 table items
包含 id (PRIMARY), name(VARCHAR), section_id (BIGINT), updated_at (DATETIME)
、
列
和 table sections
与 id (PRIMARY)
。
自然地,items.section_id
是引用sections.id
的外键。
假设在 (section_id, name)
列的 items
上有一个索引。我相信如果你试图删除这个索引,你会得到一个错误,它是 needed in a foreign key constraint
。这个我可以接受。
现在,我想创建一个新索引,例如 create index ix_section_id_id_updated_at on items (section_id, id, updated_at)
。 MySQL 让我这样做,但是如果我去删除这个 table,我会得到同样的错误:它失败了,因为它是 needed in a foreign key constraint
.
为什么会这样?它已经有一个可用于此外键检查的索引。此外,错误不会随着 set FOREIGN_KEY_CHECKS=0;
消失。有没有办法强制MySQL不把新索引和外键联系起来,这样就快drop了?这是必要的,因为我将 运行 在临时停机的生产服务器上进行迁移,并且需要能够在之后出现任何问题时快速恢复迁移。
如果我不在 section_id 上创建索引并允许 mysql 在创建外键时这样做(如手册中所述),我可以重现您的问题。添加新索引会删除自动生成的键,如果您随后删除新索引,则会生成错误,因为需要有一个键,并且 mysql 不会在删除时自动生成一个...。如果您在 section_id 上手动生成密钥,则不会发生此问题。并且新创建的复合索引成功删除。
drop table if exists items;
drop table if exists sections;
create table items(id int PRIMARY key, name varchar(3), section_id BIGINT, updated_at DATETIME);
create table sections(id bigint primary key);
alter table items
add foreign key fk1(section_id) references sections(id);
show create table items;
CREATE TABLE `items` ( `id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk1` (`section_id`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;
alter table items
add key key1(section_id, name);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `key1` (`section_id`,`name`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
并使用手动生成的密钥
drop table if exists items;
drop table if exists sections;
create table items(id int PRIMARY key, name varchar(3), section_id BIGINT, updated_at DATETIME);
create table sections(id bigint primary key);
alter table items
add key sid(section_id);
alter table items
add foreign key fk1(section_id) references sections(id);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sid` (`section_id`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
alter table items
add key key1(section_id, name);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sid` (`section_id`),
KEY `key1` (`section_id`,`name`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
假设我有一个 table items
包含 id (PRIMARY), name(VARCHAR), section_id (BIGINT), updated_at (DATETIME)
、
和 table sections
与 id (PRIMARY)
。
自然地,items.section_id
是引用sections.id
的外键。
假设在 (section_id, name)
列的 items
上有一个索引。我相信如果你试图删除这个索引,你会得到一个错误,它是 needed in a foreign key constraint
。这个我可以接受。
现在,我想创建一个新索引,例如 create index ix_section_id_id_updated_at on items (section_id, id, updated_at)
。 MySQL 让我这样做,但是如果我去删除这个 table,我会得到同样的错误:它失败了,因为它是 needed in a foreign key constraint
.
为什么会这样?它已经有一个可用于此外键检查的索引。此外,错误不会随着 set FOREIGN_KEY_CHECKS=0;
消失。有没有办法强制MySQL不把新索引和外键联系起来,这样就快drop了?这是必要的,因为我将 运行 在临时停机的生产服务器上进行迁移,并且需要能够在之后出现任何问题时快速恢复迁移。
如果我不在 section_id 上创建索引并允许 mysql 在创建外键时这样做(如手册中所述),我可以重现您的问题。添加新索引会删除自动生成的键,如果您随后删除新索引,则会生成错误,因为需要有一个键,并且 mysql 不会在删除时自动生成一个...。如果您在 section_id 上手动生成密钥,则不会发生此问题。并且新创建的复合索引成功删除。
drop table if exists items;
drop table if exists sections;
create table items(id int PRIMARY key, name varchar(3), section_id BIGINT, updated_at DATETIME);
create table sections(id bigint primary key);
alter table items
add foreign key fk1(section_id) references sections(id);
show create table items;
CREATE TABLE `items` ( `id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk1` (`section_id`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;
alter table items
add key key1(section_id, name);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `key1` (`section_id`,`name`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
并使用手动生成的密钥
drop table if exists items;
drop table if exists sections;
create table items(id int PRIMARY key, name varchar(3), section_id BIGINT, updated_at DATETIME);
create table sections(id bigint primary key);
alter table items
add key sid(section_id);
alter table items
add foreign key fk1(section_id) references sections(id);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sid` (`section_id`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
alter table items
add key key1(section_id, name);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sid` (`section_id`),
KEY `key1` (`section_id`,`name`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;