1

我有这个超过 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约束使插入速度变慢。该digest列将采用必须唯一的 SHA256 摘要,我无法确保没有冲突(我知道,这不太可能,但可能)。

正如这里所建议的那样,分区会有所帮助吗?我可以改进索引,例如通过限制digest列上的键长度吗?我应该更改为在交易期间支持的 MyISAMDISABLE KEYS吗?我还能做些什么来提高LOAD DATA性能?

编辑:

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

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

sequenceblob 放入外部文件系统可能不是一个可行的选择,因为我不能轻易地将文件系统更改强加给用户。

4

2 回答 2

2

这确实是您正在加载的大量数据,您应该预计它会花费数十个小时,尤其是在通用共享服务器硬件上。几乎没有什么魔力(除非你在谷歌或其他什么公司工作)可以让这份工作变得不那么痛苦。所以要有勇气。

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

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

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

如果不了解您的数据和服务器硬件的更多信息,就很难提出有关分区的建议。但考虑到这是一个参考数据库,似乎只需要咬紧牙关几个星期再加载它可能是明智之举。

如果您有足够的服务器磁盘空间,您可以考虑将每个半兆块加载到自己的表中,然后将其插入到大表中。这可能被证明是一种很好的方式来处理您可能需要在某天重新加载整个内容的可能性。

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

您可能会考虑制作一个单独的 id / 摘要表。然后,您可以在没有摘要的情况下加载数据并快速完成。然后,您可以自己编写一个存储过程或客户端,以每批几千行的形式创建摘要,直到它们完成为止。这仅在被消化的内容在您的数据集中时才有效。

于 2013-01-07T16:55:28.087 回答
1

数据加载缓慢主要有两个原因:

  1. 插入数据本身的写入性能。
  2. 读取现有数据以加载现有数据以便在添加新数据时修改现有页面的性能。

可以通过主要降低持久性和减少日志记录来解决写入性能问题。这就是您会发现的许多建议,例如以下设置: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足够大),以便在加载期间不需要将数据分页进出缓存。鉴于您只谈论几百万行,这可能是可行的。

于 2013-01-08T16:30:31.567 回答