2015-12-13 53 views
1

我有以下InnoDB表:MySQL的InnoDB的:FOREIGN KEY約束性能

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; 

表車輛擁有約45.000記錄,表部分有大約3.500.000記錄和表vehicle_part有大約100.000.000記錄。 爲車輛部分創建二級索引不需要太長時間,兩者都需要大約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日

德魯給出的答案中顯着提高性能幫助很大。我使用SELECT ... INTO outfile來更改每個腳本,然後從導出的csv文件中加載LOAD DATA INFILE。有時在LOAD DATA INFILE之前刪除索引並在加載過程之後重新創建它們可節省更多時間。沒有必要放棄只有二級索引的fk約束。

+0

小記...在索引表中插入批量數據的在性能不好.....如果你能刪除索引然後插入然後生成指數再次PERF將顯着增強 –

+0

是的,這就是我所做的,並且性能有所提高,但主要問題不在於索引,而在於外鍵約束。 – pankal

+0

爲什麼你不考慮分區表,在分區上循環並按分區插入數據 –

回答

2

如果你知道你的數據是原始的從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 | 

更多鏈接

+0

但是,如果我離開FK約束,InnoDB會自動在引用列上創建二級索引,不是嗎?此外,數據是外部(csv文件),但我不能使用加載數據infile,因爲我需要加入來自不同csv文件的數據。 – pankal

+0

這是每個手冊作爲一種可能性,我會授予你。但是,如果您執行'set FOREIGN_KEY_CHECKS = 0;'並插入幾行,並執行'show create table booksAssigned',那麼您可能會發現這並不是您建議的索引的自動補丁。 – Drew

+0

是的,我總是使用FOREIGN_KEY_CHECKS = 0來執行插入操作。但是插入的時間太多了。即使是mysqldump之後也需要很長時間才能將數據導出到服務器。 – pankal