【发布时间】:2019-03-30 16:44:51
【问题描述】:
我有一个包含大约 4.2 亿条记录的大型数据集,我能够使用 LOAD DATA INFILE 语句在大约 15 分钟内将它们及时加载到临时表中。我需要这个临时表来暂存数据,因为我在将其加载到最终目的地之前对其进行了一些清理。
临时表定义为:
CREATE TABLE `temporary_data` (
`t_id` smallint(10) unsigned NOT NULL,
`s_name` varchar(512) NOT NULL,
`record_type` varchar(512) NOT NULL,
`record_value` varchar(512) NOT NULL
) ENGINE=MyISAM;
需要加载此数据的目标表称为my_data,其定义为:
CREATE TABLE `my_data` (
`s_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`t_id` smallint(10) unsigned NOT NULL,
`s_name` varchar(63) NOT NULL,
PRIMARY KEY (`s_id`),
UNIQUE KEY `IDX_MY_DATA_S_NAME_T_ID` (`t_id`,`s_name`) USING BTREE,
KEY `IDX_MY_DATA_S_NAME` (`s_name`) USING BTREE,
CONSTRAINT `FK_MY_DATA_MY_PARENT` FOREIGN KEY (`t_id`) REFERENCES `my_parent` (`t_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
问题是,将临时表中的数据加载到my_data 的查询非常慢,因为我怀疑这是因为my_data 包含两个索引和一个主键。到目前为止,这个查询已经运行了 6 个多小时:
INSERT IGNORE INTO my_data (t_id, s_name)
SELECT t_id, s_name
FROM temporary_data;
我需要确定一种方法来加快此查询的速度,以便及时完成(最好在 30 分钟内完成)。
我考虑过的一些方法:
-
禁用索引:我可能能够通过禁用/删除
IDX_MY_DATA_S_NAME索引而侥幸成功,但我依靠唯一索引 (IDX_MY_DATA_S_NAME_T_ID) 来保持数据清洁。这是一个每天都会自动运行的过程,不可避免地会有一些重复。另外,当我再次启用索引时,在这么大的数据集上重建索引似乎同样耗时。 -
使用 DATA OUTFILE: 将清理后的数据直接导出并重新导入到
my_data。我在某处看到了这个推荐,但在考虑之后,索引/PK 仍然是重新插入的争论点。 -
交换表格: 将
my_data替换为temporary_data听起来很吸引人,但该表格对于s_id字段有很多外键关系,因此我希望确保这种方法值得麻烦禁用外键并重新启用它们。子表包含的记录将明显少于my_data,因此在这方面重新启用外键可能可以忽略不计。 -
LOAD DATA INFILE directly: 使用语句的 SET 部分中的条件将数据直接加载到
my_data以使所有字段NULL当它不符合我最初应用于 @ 的清理标准时987654338@ 在将其加载到my_data之前。这很 hacky,但它依赖于假设 LOAD DATA INFILE 将比 INSERT 更快... SELECT 即使面对索引,由于表上的唯一约束,在运行后只会删除一行空值.
这些听起来都不是非常棒的想法。如果有人有任何提示,我会全力以赴。
【问题讨论】:
-
show status like '%inno%wait%';显示什么? -
Innodb_buffer_pool_wait_free 0 Innodb_log_waits 0 Innodb_row_lock_current_waits 0 Innodb_row_lock_waits 0
-
我正在使用每个表模式的单独文件,我看到 .ibd 文件继续增长。
show processlist表明它也在sending data状态下执行。 -
查看技巧和技巧here。
-
感谢您的链接。我一定会检查出来的。
标签: mysql bigdata large-data load-data-infile