【问题标题】:MySQL - how long to create an index?MySQL - 创建索引需要多长时间?
【发布时间】:2011-01-29 19:19:13
【问题描述】:

谁能告诉我如何在 MySQL 中添加键缩放?我在数据库中有 500,000,000 行,trans,列 i (INT UNSIGNED)、j (INT UNSIGNED)、nu (DOUBLE)、A (DOUBLE)。 我尝试索引一列,例如

ALTER TABLE trans ADD KEY idx_A (A);

我等着。对于 14,000,000 行的表,在我的 MacBook Pro 上执行大约需要 2 分钟,但对于整个 50 亿行,它需要 15 小时并且还在增加。是我做错了什么,还是我只是对索引数据库如何随行数扩展而天真?

【问题讨论】:

  • 您可能想考虑拆分(数据库分片)您的表

标签: mysql indexing


【解决方案1】:

有几个因素需要考虑:

  • 排序是一个 N.log(N) 操作。
  • 14M 行的排序可能很适合主内存;具有 500M 行的排序可能不会,因此排序会溢出到磁盘,这会大大减慢速度。

由于因子的大小约为 30,因此大数据集的标称排序时间大约是 50 倍 - 不到两个小时。但是,每个数据值需要 8 个字节和另外 8 个字节的开销(这是一个猜测——如果您对 mySQL 存储在索引中的内容了解更多,请调整它)。因此,14M × 16 ≈ 220 MB 主存。但是 500M × 16 ≈ 8 GB 主内存。除非你的机器有这么多的内存可用(并且 MySQL 被配置为使用它),否则大的排序会溢出到磁盘,这占了其余时间的大部分时间。

【讨论】:

  • 非常感谢,这对我来说很有意义 - 我只有 4 GB。看起来像上面建议的那样拆分(分区?)数据很有意义。
  • 你拆分了你的桌子吗?花了多长时间?
【解决方案2】:

首先,您的表定义在这里可能会产生很大的不同。如果您的列中不需要NULL 值,请定义它们NOT NULL。这将节省索引空间,并可能在创建索引时节省时间。

CREATE TABLE x ( 
  i INTEGER UNSIGNED NOT NULL, 
  j INTEGER UNSIGNED NOT NULL, 
  nu DOUBLE NOT NULL, 
  A DOUBLE NOT NULL 
);

至于创建索引所花费的时间,这需要进行一次表扫描,并且会显示为REPAIR BY SORTING。在您的情况下(即海量数据集)应该更快地创建具有所需索引的新表并将数据插入其中,因为这将避免 REPAIR BY SORTING 操作,因为索引是在插入时按顺序构建的。 this article 中解释了类似的概念。

CREATE DATABASE trans_clone;
CREATE TABLE trans_clone.trans LIKE originalDB.trans;
ALTER TABLE trans_clone.trans ADD KEY idx_A (A);

然后将插入脚本编写成块(根据文章),或使用MYSQLDUMP 转储数据:

mysqldump originalDB trans  --extended-insert --skip-add-drop-table --no-create-db --no-create-info > originalDB .trans.sql
mysql trans_clone < originalDB .trans.sql

这将插入数据,但不需要重建索引(索引是在插入每一行时构建的)并且应该更快地完成。

【讨论】:

  • 请注意,您可以使用 Percona Toolkit 中的 pt-online-schema-change,而不是执行 mysqldump 和在整个过程中至少需要连续的表读取锁定的恢复 - 它会处理多次创建和复制数据,消除连续锁定要求。
【解决方案3】:

根据我的经验:如果硬件可以应付,使用 MySQL 索引大型表通常可以非常线性地扩展。到目前为止,我已经用大约 100,000,000 行的表进行了尝试,但不是在笔记本上 - 主要是在强大的服务器上。

我想这主要取决于硬件因素、您使用的表格引擎类型(MyIsam、INNO 或其他)以及表格是否在两者之间使用。当我这样做时,通常磁盘使用率会飙升,这与 CPU 使用率不同。不确定 MacBook 的硬盘,但我猜它们不是最快的。

如果您有 MyISAM 表,不妨仔细查看表目录中的索引文件,看看它随时间的变化。

【讨论】:

  • 感谢您的快速回复,比约恩。我听从了你的建议。我认为文件#sql-a8_6.MYD(当前为7,455,506,432字节)和#sql-a8_6.MYI(当前为2,148,865,024字节)分别是正在构建的数据库的新版本和我请求的索引?那么如果原始表是 trans.MYD (12,645,156,375 字节),我大约完成了 60%?开始看起来我最好把这张大桌子分成 20 个左右的小桌子。谢谢,克里斯蒂安
  • 总的来说应该是这样。嗯,这完全取决于你想用这些数据量做什么。 500.000.000 行很多,所以如果您想在之后做一些花哨的报告,请尝试最小化数据。要么尝试拆分它,要么利用 MySQL 的分区功能(从 5.1 版开始)。
【解决方案4】:

所以理论上如果排序步骤是 N.log(N) 操作,对大表进行分区将节省操作时间

在 100 个相等文件中分区的 500 000 000 行表的增益约为 30%:因为 500 000 000* 对数(500 000 000)= 4 349 485 002 和 100 *(500 000 000/100*LOG(500 000 000/100)) = 3 349 485 002

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    相关资源
    最近更新 更多