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

Dav*_*rks 14 mysql innodb myisam performance

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

我现在正在尝试使用 InnoDB。负载以超过 10MB/秒的速度快速启动(观察表文件增长,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....
Run Code Online (Sandbox Code Playgroud)

我不明白为什么它开始良好并随着时间的推移放缓。

此外,使用相同的设置,我使用 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
Run Code Online (Sandbox Code Playgroud)

我的ISAM:

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
Run Code Online (Sandbox Code Playgroud)

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


额外细节:

  • 我试过单独加载文件,没有区别。

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

  • 一夜之间获得40GB,12小时后,负载率下降到0.5MB/秒,这意味着操作实际上是不可能的。

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

Rol*_*DBA 7

观察#1

我注意到你关机了autocommit。那将在ibdata1中堆积如此多的数据。为什么?

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

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

根据隔离级别,某些信息对某些事务可见。此类操作可能会产生意外的主键锁大量幻像数据。随着这两件事的增加,您应该预期会放缓。

建议:启用自动提交

观察#2

我看到你有这个:

alter table item_load disable keys;
Run Code Online (Sandbox Code Playgroud)

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

  • MyISAM :DISABLE KEYS简单地关闭 MyISAM 表的二级索引更新。当您在禁用键的情况下将 INSERT 批量插入 MyISAM 表时,会导致快速表加载以及 PRIMARY KEY 和所有唯一索引的构建。运行时ENABLE KEYS,所有二级索引都在表上线性构建并附加到.MYD.
  • InnoDB :如InnoDB的内部图片所示,系统tablepaveibdata1有一个专用于二级索引插入的结构。目前,没有规定像 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>
Run Code Online (Sandbox Code Playgroud)

观察 #3

您注意到 MyISAM 的加载速度比 InnoDB 快 20 倍。你想让它快 24-25 倍吗?然后运行以下命令:

ALTER TABLE item_load ROW_FORMAT=Fixed;
Run Code Online (Sandbox Code Playgroud)

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

您也可以在 InnoDB 表上运行它,但是 InnoDB 的ACID 兼容行为MVCC仍然是其性能的瓶颈,特别是如果 VARCHAR 字段显着增加被写入ibdata1.


Dav*_*rks 6

这个问题的最终答案是不要将 InnoDB 用于大量引用表。MyISAM 的速度快得惊人,整个负载的磁盘速度接近全吞吐量,InnoDB 陷入困境。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