mysql InnoDB : FOREIGN KEY constraint performance

标签 mysql performance foreign-keys innodb

我有以下 InnoDB 表:

 CREATE TABLE `vehicle` (
  `ID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(50) DEFAULT NULL,
  `Model` varchar(100) DEFAULT NULL,
  `Engine_Type` varchar(70) DEFAULT NULL,
  `Construction_From` date DEFAULT NULL,
  `Construction_To` date DEFAULT NULL,
  `Engine_Power_KW` mediumint(8) unsigned DEFAULT NULL,
  `Engine_Power_HP` mediumint(8) unsigned DEFAULT NULL,
  `CC` mediumint(8) unsigned DEFAULT NULL,
  `TTC_TYP_ID` int(11) unsigned DEFAULT NULL,
  `Vehicle_Type` tinyint(1) DEFAULT NULL,
  `ID_Body_Type` tinyint(3) unsigned DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=49407 DEFAULT CHARSET=utf8;

CREATE TABLE `part` (
  `ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `ID_Brand` smallint(5) unsigned DEFAULT NULL,
  `Code_Full` varchar(50) DEFAULT NULL,
  `Code_Condensed` varchar(50) DEFAULT NULL,
  `Ean` varchar(50) DEFAULT NULL COMMENT 'The part barcode.',
  `TTC_ART_ID` int(11) unsigned DEFAULT NULL COMMENT 'TecDoc ID.',
  `ID_Product_Status` tinyint(3) unsigned DEFAULT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `TTC_ART_ID_UNIQUE` (`TTC_ART_ID`),
  UNIQUE KEY `ID_Brand_Code_Full_UNIQUE` (`ID_Brand`,`Code_Full`)
) ENGINE=InnoDB AUTO_INCREMENT=3732260 DEFAULT CHARSET=utf8;

CREATE TABLE `vehicle_part` (
  `ID_Vehicle` mediumint(8) unsigned NOT NULL,
  `ID_Part` int(11) unsigned NOT NULL,
  PRIMARY KEY (`ID_Vehicle`,`ID_Part`),
  KEY `fk_vehicle_part_vehicle_id_vehicle_idx` (`ID_Vehicle`),
  KEY `fk_vehicle_part_part_id_part_idx` (`ID_Part`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

表vehicle大约有45.000条记录,表part大约有3.500.000条记录,表vehicle_part大约有100.000.000条记录。 为 vehicle_part 创建二级索引并没有花费太长时间,大约都是 30 分钟。 但我不能做的是创建外键约束:例如

ALTER TABLE `vehicle_part` 
ADD CONSTRAINT `fk_vehicle_part_vehicle_id_vehicle`
  FOREIGN KEY (`ID_Vehicle`)
  REFERENCES `vehicle` (`ID`)
  ON DELETE NO ACTION
  ON UPDATE NO ACTION;

需要很长时间才能完成。我知道该表已重建,因为它消耗了大量磁盘空间。我可以做什么来提高性能? 如果我使用 fk 约束创建表,然后添加记录,则在 Vehicle_part 中的插入过程也需要很长时间(大约 3 天)。 我使用的是 4GB RAM 的笔记本电脑。

编辑2016年12月1日

Drew 给出的答案对于大幅提高性能有很大帮助。我使用 SELECT ... INTO outfile 更改了每个脚本,然后从导出的 csv 文件中加载数据 INFILE。有时,在 LOAD DATA INFILE 之前删除索引并在加载过程后重新创建它们可以节省更多时间。无需删除 fk 约束,只需删除二级索引即可。

最佳答案

如果您知道您的数据从 FK 角度来看是原始的,那么请按照注释中的建议建立不使用二级索引的结构,但在架构中使用 FK,但暂时禁用 FK 检查。

加载您的数据。如果是外部数据,当然要使用LOAD DATA INFILE。

加载数据后,打开 FK 检查。并通过Alter Table建立二级索引。

再次假设您的数据是干净的。对于厌恶风险的人来说,事后还有其他方法可以证明这一点。

create table student
(   id int auto_increment primary key,
    sName varchar(100) not null
    -- secondary indexes to be added later
);

create table booksAssigned
(   id int auto_increment primary key,
    studentId int not null,
    isbn varchar(20) not null,
    constraint foreign key `fk_b_s` (studentId) references student(id)
    -- secondary indexes to be added later
);


insert booksAssigned(studentId,isbn) values (1,'asdf'); -- Error 1452 as expected

set FOREIGN_KEY_CHECKS=0; -- turn FK checks of temporarily

insert booksAssigned(studentId,isbn) values (1,'asdf'); -- Error 1452 as expected

set FOREIGN_KEY_CHECKS=1; -- succeeds despite faulty data

insert booksAssigned(studentId,isbn) values (2,'38383-asdf'); -- Error 1452 as expected

根据操作评论,如何在初始架构创建后在引用表中删除自动生成的索引:

mysql> show create table booksAssigned;

| booksAssigned | CREATE TABLE `booksassigned` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `studentId` int(11) NOT NULL,
  `isbn` varchar(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_b_s` (`studentId`),
  CONSTRAINT `booksassigned_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`)
) ENGINE=InnoDB |

mysql> set FOREIGN_KEY_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)

mysql> drop index `fk_b_s` on booksAssigned;
Query OK, 0 rows affected (0.49 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table booksAssigned;

| booksAssigned | CREATE TABLE `booksassigned` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `studentId` int(11) NOT NULL,
  `isbn` varchar(20) NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `booksassigned_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`)
) ENGINE=InnoDB |

更多链接

关于mysql InnoDB : FOREIGN KEY constraint performance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34254045/

相关文章:

mysql - 向具有外键约束的表添加行 [MySQL]

mysql - 对 Wordpress 数据库的查询返回帖子的无效类别

mysql - 超过mysql每小时最大连接数

python - 将迭代器传递给 any 以提高执行速度,为什么?

android - 有什么优化的方法可以在 android 中呈现大列表吗?

sql - 在 PgAdmin 中添加外键

mysql - 如何从表的所有列中判断某列是否是表的主键?

mysql - 如何在不影响性能的情况下将mysql的100万条记录从一台机器传输到另一台机器

java - Exceptions 有多昂贵

java - 使用 ListView 检索数据的 SQLite 外键语法出现问题