在MySQL(MariaDB)中的大型表上创建索引需要花费很多时间

时间:2015-01-19 16:27:30

标签: mysql mariadb

我有一个包含几十亿行数据的表,我正在尝试一次构建5个索引。表格格式为MyISAM以节省空间。一旦我构建索引,这将是一个静态表,我只需要它是只读的。

我使用此命令创建了索引:

alter table links8添加索引(uid,tid),添加索引(日期),添加索引(tid),添加索引(userid),添加索引(更新,uid,tid,userid,日期);

该命令已运行超过45天。你看对了:45天。我可以看到临时文件仍然被访问,它不是一个死的查询。

我的问题是:wtf?似乎最多需要花费几个小时来排序和构建索引,即使行数为几十亿。

由于我有一个静态表,是否有另一个有意义的存储引擎? Innodb占用太多空间。

2 个答案:

答案 0 :(得分:0)

45天似乎没有问题,因为在那个时候,MySQL肯定会做一些事情,并且有可能消耗RAM或存储,可能两者都有,这意味着你应该已经用完了一点。 我假设它是RAM,因为这通常是事情变得稀疏的地方;)

现在,你是绝对正确的,在内存中排序数十亿的价值不应该花费很长时间。对(updated,uid,tid,userid,date)中连接值的几十亿个值进行排序,尽管很可能不会在RAM中发生。假设updateddate属于datetime类型,它们各占8个字节; uidtiduserid通常为32位整数,但由于您的表格有> 2 ** 32个条目(I' m假设),唯一ID也是8个字节长。因此,类型(updated,uid,tid,userid,date)的一个值将是40B长。

现在让我们说50亿这些;您将获得200 GB的纯行数据,您需要对其进行排序以构建索引。假设你没有在某台大型计算机上执行此操作,显然需要将这些值的一部分交换到磁盘 - 因为你看到临时文件出现了,我猜测这种情况正在发生,并且MySQL正在积极地这样做本身。现在,迭代地处理部分行的排序算法要慢得多,因为首先对所有部分进行排序,然后以比以前更好的排序方式混合部分,而不是重新划分数据,你可以对零件进行分类......在磁盘之间存储和加载。

顺便说一下,如果不采取纠正措施,那么45天的持续内存操作很可能容易出现内存位错误(基本上,这种任务使用ECC,或者你最终得到索引的,损坏的数据)

MySQL自己suggest你只是建立一个特殊的MD5索引,它接受你的搜索元组的哈希并查找它,因为排序128位(== 16字节)MD5哈希可能比排序5 * 8Byte更容易== 40 * 8位== 320位长复合行。

答案 1 :(得分:0)

我找到了更好的解决方案。

我创建了一个新表,其中已有索引,然后从一个表向另一个表发出插入。它的工作方式是填充MYD(原始数据文件),然后在此之后创建索引。一旦它开始创建索引,我就终止了查询。然后在文件系统上我使用myisamchk手动修复表。

该命令看起来像这样:

myisamchk --force --fast --update-state --key_buffer_size = 2000M --sort_buffer_size = 2000M --read_buffer_size = 10M --write_buffer_size = 10M TABLE.MYI

整个过程花了不到12个小时,数据看起来不错!

更新:

以下是汇总的流程。

使用索引创建table2与table1的缩进;

插入table2 select * from table1;

一旦MYD文件已满,它就会从MYI文件开始终止查询

然后关闭mysql并运行myisamchk查询并重启mysql

OR

将table2.MYD和table2.MYI复制到table3.MYD和table3.MYI,然后运行myisamchk,然后将table2.frm复制到table3.frm并更改权限,当它完成后你应该能够访问table3而不重启mysql