如何在大型InnoDB表上提高LOAD DATA性能?

时间:2013-01-07 15:47:52

标签: mysql performance innodb load-data-infile

我有超过700万行的这个表,我LOAD DATA LOCAL INFILE一次有大约50万行的数据CREATE TABLE `orthograph_ests` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `digest` char(32) NOT NULL, `taxid` int(10) unsigned NOT NULL, `date` int(10) unsigned DEFAULT NULL, `header` varchar(255) NOT NULL, `sequence` mediumblob, PRIMARY KEY (`id`), UNIQUE KEY `digest` (`digest`), KEY `taxid` (`taxid`), KEY `header` (`header`) ) ENGINE=InnoDB AUTO_INCREMENT=12134266 DEFAULT CHARSET=latin1 。前几次很快,但这种增加的时间越来越长,可能是因为索引开销:

UNIQUE

我正在开发一个可在预先存在的数据库上运行的应用程序。我很可能无法控制服务器变量,除非我强制更改它们(我不愿意),所以我担心像these这样的建议用途有限。

我已经读到最小化此表上的键会有所帮助。但是,我需要这些密钥以供以后查询。我猜测如果我放弃并重新创建它们也需要很长时间,但我还没有测试过。我还读过,特别是digest约束使插入变慢。 digest列将采用必须唯一的SHA256摘要,并且我无法确保没有碰撞(我知道,这是非常不可能的,但可能)。

分区帮助,如建议here?我可以改进索引,例如,通过限制DISABLE KEYS列上的密钥长度吗?我应该更改为MyISAM,它在转码期间支持LOAD DATA吗?我还能做些什么来提高SELECT表现?

修改

大插入后,此表仅用于sequence,不再写入。这种大型加载大多是一次性完成的操作,但是在完成之前需要上传大约1,000个数据集(每个0.5M行)。

我将使用摘要查找行,这就是我为该列编制索引的原因。如果应该发生冲突,则不应上载该单独的行。

将{{1}} blob放在外部文件系统中可能不是一个可行的选择,因为我不能轻易地对用户强加文件系统更改。

2 个答案:

答案 0 :(得分:2)

这确实是您要加载的大量数据,您应该需要花费数十个小时,尤其是在通用共享服务器硬件上。没有什么魔力(除非你在谷歌或其他什么地方工作),这将使这项工作成为一个巨大的痛苦。所以要有勇气。

这是一张参考表。这意味着您应立即切换到MyISAM并留在此表中。您不需要InnoDB的事务完整性功能,但是您需要MyISAM在加载期间禁用索引并在之后重新启用它。重新启用索引将需要很长时间,因此请做好准备。

您应该考虑使用比SHA-256更短的哈希值。 SHA-1(160位)很好。信不信由你,MD-5(128位)也可以服务。 MD-5已被破解,因此不适合安全内容认证。但它仍然是一个有用的哈希。从您的角度来看,较短的哈希是更好的哈希。

如果您可以禁用索引MyISAM样式,那么您的摘要键是否唯一可能无关紧要。但是你可以考虑允许它不是唯一的以节省时间。

如果不了解有关数据和服务器硬件的更多信息,很难对分区提出建议。但是考虑到这是一个参考数据库,看起来好像只是咬了几个星期然后加载它。

如果你有足够的服务器磁盘空间,你可以考虑将每个half-megarow块加载到自己的表中,然后将其插入到大表中。这可能是一种很好的方法来处理你可能有一天需要重新加载整个东西的可能性。

在共享服务器硬件上,使用比megarow一半更小的块可能是有意义的。

您可以考虑制作单独的ID /摘要表。然后,您可以在没有摘要的情况下加载数据并快速完成。然后你可以自己编写一个存储过程或客户端,它们将分别创建几千行的摘要,直到完成为止。这仅适用于正在消化的内容位于数据集中的情况。

答案 1 :(得分:1)

数据加载速度基本上有两个原因:

  1. 在插入数据本身时写入性能。
  2. 读取现有数据的性能,以便加载现有数据,以便在添加新数据时修改现有页面。
  3. 写入性能问题可以通过主要降低持久性和减少日志记录来解决。这就是您可以找到的许多建议,例如以下设置:innodb_flush_log_at_trx_commit=0innodb_doublewrite=0innodb_support_xa=0。减少所写数据的金额也很有帮助,例如设置log-bin=0。但是,期望您的客户在现有生产系统中更改这些与耐久性相关的设置并不是真的可以接受。更改它们更适合在专用系统上进行一次性批量加载,而不是定期向现有系统添加数据。

    批量加载INSERT(包含多行)或LOAD DATA INFILE通过在单个事务中写入更多数据来寻求降低写吞吐量要求,从而减少同步数量到事务日志。尽管如此,降低写入吞吐量或提高写入性能只会有所帮助。

    在加载之前,通过PRIMARY KEY对数据进行排序通常也很有帮助,以便在将数据插入索引结构时减少不必要的页面拆分量。但是,当存在多个辅助密钥时,这种用途有限,因为按PRIMARY KEY排序必然意味着数据未按至少一个辅助密钥排序。

    读取性能问题可能更有趣,并且通常是将新数据加载到现有表中的实际性能问题,尤其是在存在辅助键的情况下。最好的办法是所有现有数据都适合内存(innodb_buffer_pool_size足够大),这样在加载过程中不需要在缓存中进出分页数据。鉴于您只谈论了几百万行,这可能是可行的。