在使用InnoDB引擎输入数次演出后,MySQL LOAD DATA INFILE速度降低了80%


14

我正在通过LOAD DATA INFILE加载100GB文件。我在MyISAM上取得了成功,几个小时就完成了。

我现在正在尝试使用InnoDB。负载以超过10MB / sec的速度快速启动(监视表文件的增长file_per_table是否已打开)。

但是,在大约5GB的数据传输之后,它会降低到2-4MB /秒的范围,而当我超过20GB时,它的传输速度会降低到2MB /秒左右。

InnoDB缓冲池的大小为8G。在运行LOAD DATA INFILE命令之前,我已经完成了以下操作:

SET @@session.sql_log_bin=0;
SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;
alter table item_load disable keys;
//Run LOAD DATA INFILE....

我看不出它启动良好并随着时间的推移变慢的原因。

另外,使用相同的设置,我使用InnoDB和MyISAM和5GB测试数据集对表运行了相同的LOAD DATA INFILE命令,MyISAM快20倍:

InnoDB:

mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 2630886 rows affected, 6 warnings (21 min 25.38 sec)
Records: 2630886  Deleted: 0  Skipped: 0  Warnings: 6

MyISAM:

mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 2630886 rows affected, 6 warnings (1 min 2.52 sec)
Records: 2630886  Deleted: 0  Skipped: 0  Warnings: 6

还有什么我应该考虑尝试的吗?MyISAM引擎能够更好地保持负载率。


额外细节:

  • 我尝试过分别加载文件,没有区别。

  • 顺便说一句,我有150个500MB的文件,每个文件中的键都是排序的。

  • 在隔夜12小时后获得40GB的存储空间后,加载速度降至0.5MB /秒,这实际上意味着该操作是不可能的。

  • 我在其他论坛上都没有找到类似问题的其他答案,在我看来,InnoDB不支持将大量数据加载到大小超过GB的表中。

Answers:


7

观察#1

我注意到你关了autocommit。这将在ibdata1中堆积大量数据。为什么?

ibdata1中存储了七(7)类信息:

  • InnoDB表的数据页
  • InnoDB表的索引页
  • 数据字典
  • 双写缓冲区
    • 安全网,防止数据损坏
    • 帮助绕过操作系统进行缓存
  • 插入缓冲区(简化对二级索引的更改)
  • 回滚段
  • 撤消日志
  • 单击此处以查看的图片表示 ibdata1

根据隔离级别,某些交易可以看到某些信息。此类操作可能会产生意外的主键锁定大量的幻像数据。随着这两种情况的增加,您应该可以放慢脚步。

建议:启用自动提交

观察#2

我看到你有这个:

alter table item_load disable keys;

DISABLE KEYS不适用于InnoDB。原因如下:

  • MyISAM:DISABLE KEYS只需关闭MyISAM表的辅助索引更新。当您在禁用键的情况下将INSERT批量装入MyISAM表时,将导致快速表加载以及PRIMARY KEY和所有唯一索引的构建。运行时ENABLE KEYS,所有二级索引都线性地建立在表上,并附加到.MYD
  • InnoDB:如InnoDB的内部图片所示,系统表spave ibdata1具有专用于二级索引插入的结构。当前,没有规定可以处理与MyISAM相同的索引。

为了说明这一点,请注意我在MySQL的InnoDB表上运行DISABLE KEYS的尝试。

mysql> show create table webform\G
*************************** 1. row ***************************
       Table: webform
Create Table: CREATE TABLE `webform` (
  `nid` int(10) unsigned NOT NULL,
  `confirmation` text NOT NULL,
  `confirmation_format` tinyint(4) NOT NULL DEFAULT '0',
  `redirect_url` varchar(255) DEFAULT '<confirmation>',
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `block` tinyint(4) NOT NULL DEFAULT '0',
  `teaser` tinyint(4) NOT NULL DEFAULT '0',
  `allow_draft` tinyint(4) NOT NULL DEFAULT '0',
  `submit_notice` tinyint(4) NOT NULL DEFAULT '1',
  `submit_text` varchar(255) DEFAULT NULL,
  `submit_limit` tinyint(4) NOT NULL DEFAULT '-1',
  `submit_interval` int(11) NOT NULL DEFAULT '-1',
  PRIMARY KEY (`nid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> alter table webform disable keys;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+-------------------------------------------------------------+
| Level | Code | Message                                                     |
+-------+------+-------------------------------------------------------------+
| Note  | 1031 | Table storage engine for 'webform' doesn't have this option |
+-------+------+-------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select version();
+------------+
| version()  |
+------------+
| 5.5.27-log |
+------------+
1 row in set (0.00 sec)

mysql>

观察#3

您注意到MyISAM的加载速度比InnoDB快20倍。您是否希望将速度提高24-25倍?然后运行以下命令:

ALTER TABLE item_load ROW_FORMAT=Fixed;

无需任何其他DDL更改,这将使INSERT速度提高20-25%。副作用:MyISAM表的大小可以增长80%-100%,甚至可能更大。

您也可以在InnoDB表上运行此命令,但是InnoDB的ACID兼容行为MVCC仍将是其性能的瓶颈,尤其是如果将VARCHAR字段显着增加的情况写入ibdata1


前两个观察是我在发现问题后尝试添加的一些东西,我的第一个尝试自然是不理会innodb(只需关闭bin日志记录)。在第3次观察中,我的数据大小在长度上高度可变,我认为这将是一个问题吗?我感觉我只需要把这张桌子放在桌子上即可。
大卫·帕克斯

6

这个问题的最终答案是不要将InnoDB用于庞大的参考表。InnoDB陷入困境,MyISAM尖叫得很快,接近整个负载的磁盘速度的全部吞吐量。MyISAM很简单,但是在这种情况下,此表的要求也是如此。对于一个简单的参考表,该表具有通过LOAD DATA INFILE进行批量加载的功能,到目前为止,MyISAM是不错的选择。

但是请注意,如果您同时运行MyISAM和InnoDB表,则都需要考虑2种缓存机制的内存分配,每个引擎都有自己的独特缓存,需要单独的内存分配。


5

您可以尝试将输入文件拆分为较小的块。

我个人 为此使用http://www.percona.com/doc/percona-toolkit/2.1/pt-fifo-split.html

如果在导入期间获得表的表锁,会发生什么情况?也许InnoDB的行级锁定会减慢它的速度(MyISAM使用表锁)。

您还可以在此处阅读以获取进一步的想法:http : //derwiki.tumblr.com/post/24490758395/loading-half-a-billion-rows-into-mysql


我的文件已经有500MB的块,我正在通过一个命名管道将它们全部管道化,以使加载更加容易,但是现在我将尝试这种方法。
戴维·帕克斯

在这里没有看到任何区别,很快我就看到了从数据库文件的11MB /秒扩展到6MB(大约2GB)的数据速度下降,并且还在继续下降。我正在for循环中加载所有文件,分别执行mysql调用。
大卫·帕克斯

第一个文件在54s中加载,第二个在3m39s中加载,第二个在3m9s,4m7s,5m21s中运行,依此类推。所有文件的大小均相同。
大卫·帕克斯

2

如果您的PK不是AUTO_INCREMENT或csv文件中的数据未按PK排序,则可能会影响数据加载的性能。由于MySQL中的表是索引,因此所有数据均按排序顺序存储,因此,如果PK值不在AUTO_INCREMENT上,则MySQL必须进行大量数据移位才能按排序顺序存储数据。这是表大小开始增长时数据加载速度变慢的原因。

我正在使用LOAD DATA INFILE在AUTO_INCREMENT上使用PK加载91GB的csv文件,但吞吐率没有下降。我每秒获得140K到145K的插入。使用Percona MySQL 5.6.38

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.