数亿数据后,MySQL / MariaDB的插入速度缓慢

时间:2019-01-21 04:06:05

标签: python mysql mariadb innodb

我正在做一个项目,要求我生成数十亿个唯一代码。目前,我使用带有InnoDB引擎和python的MariaDB生成随机唯一代码,每个生成周期插入5000个唯一代码批处理。

我的表结构:

row_id int              --primary key + autoincrement
unique_code varchar(10) --unique

问题: 当我碰到5000亿个独特的代码时,Insert变得非常缓慢,我仍然需要生成多达30亿个代码。在创造这么多记录之前,我可以在几个小时内插入300-400百万个唯一代码。

感谢任何帮助,谢谢!

更新(19年1月22日) 回答Rick James'解决方案。 这是一些生成的代码示例:

RLXT$CPS1Y
Y4P$9K70WO
PKSTY9M$FR
T$0VEFL2B1
RX4$MEKVQL

我的服务器具有32GB的RAM和相对较快的SAS硬盘,我认为它足以满足我的需求(不是吗?)。

根据我的经验,TokuDB的插入速度较慢,在达到100m记录之前还比较费力,所以我当时去了InnoDB。

对于我之前提到的事务:是的,一次插入5000条记录。直到150m的代码,它是如此之快,之后我注意到速度随着记录的增长而逐渐下降。现在我达到800m的代码,插入周期(5000个记录)需要10到15秒。

我正在使用自动增量ID来对记录进行排序和标记,因为这些代码将被转移到另一个数据库进行打印(生产)。因此,我需要知道哪些代码已传输而哪些代码尚未传输。

我将等待进一步的回答,同时我将尝试Rick's suggestions。谢谢!

2 个答案:

答案 0 :(得分:0)

尝试使用MySQL索引(如果您的服务器配置不是很好,则必须升级内存大小等)

答案 1 :(得分:0)

给我们看一下前10个值的样本。

这就是为什么您可能会“碰壁”的原因...索引可以(在一个级别上)分为两种类型:

  • 连续的,例如AUTO_INCREMENT值或TIMESTAMPs,您可以按时间顺序甚至近似按时间顺序插入行。这些值插入到表或索引的“末尾”,并且仅命中BTree的最后一个块(或几个块)。通过将所有活动划分为几个块,可以执行很少的I / O。

  • 随机数,例如UUID,MD5和其他“随机”值,大概包括您的值。在这种情况下,要插入表/索引的“下一个”值不太可能仍会缓存在RAM中。因此需要I / O。虽然表不是太大,但是所有索引块都可以保存在RAM中,因此几乎不需要I / O。但是,当索引大于缓存之后,添加“下一个”值的操作通常需要执行I / O。您的过程将会越来越慢。

该怎么办?

计划A:插入所有行后,在“ ”之后添加“随机”索引。添加索引将非常慢,但从长远来看可能会更快,因为它可以使用其他算法。

计划B:不要预先创建所有值。而是在需要时创建下一个。

计划C:购买足够的RAM以将“随机”索引完全保留在RAM中。 (计划将索引大小设为原来的两倍左右。)

计划D:您尝试过TokuDB吗?我希望它在陷入严重麻烦之前能够生存更长的时间。你的经验是什么。

您提到了交易。请详细说明。您是说每5000个代码在一次交易中都是INSERTed吗?那可能是最佳的。

您使用什么字符集和排序规则作为唯一编号?您可能应该使用ascii和ascii_bin -为了提高速度并避免大小写折叠问题。

然后...这是关于如何生成它们的另一种想法。您将不必再检查唯一性,因为它们将生成唯一:

将您的10个字符的字符串视为以整数的base-95编码形式编码的数字。 (或者您允许使用许多不同的字符)。我们将顺序生成数字,将其转换为字符串,然后将其随机化。

“下一个”值被计算为超出“当前”值的随机值。随机值必须介于1到某个增量之间,该增量可能约为10亿(这取决于您最终想要多少个数字,字符集等)

INSERT的5K(或其他任何数量)批处理成没有索引的MyISAM表。

完成后,请执行以下操作:

CREATE TABLE real (
    id ... AUTO_INCREMENT, -- do you really need this??
    random CHAR(10), NOT NULL CHARSET ascii COLLATE ascii_bin,
    PRIMARY KEY(id),   -- what for?
    INDEX(random)   -- uniqueness has been checked
INSERT INTO real (random)
    SELECT random FROM myisam_table
        ORDER BY RAND();

这是如何执行:

  1. 从本质上是一个平面文件(MyISAM表)中获取所有“随机”字符串。
  2. 使用unix排序对其进行加扰。
  3. INSERT将它们放入real表中,随即创建顺序的ids

注意:这将创建一个巨大的撤消表,因此请确保具有大量磁盘空间。

至于我对放弃idUNIQUE等的评论,请提供有关您打算如何使用real的信息,因此我可以同意或反对它们的使用。需要。

另一个计划

不预先生成值。取而代之的是,从大约14T的可能值中生成一个新值,检查是否存在重复,并在必要时生成另一个。在该计划中,表格会根据需要逐渐增长,而不必为最初构建表格而费力。取而代之的是,每当需要一个新的值时,就会花费一点努力(毫秒)。可以将其包装在“存储的函数”中,以方便用户使用。

该表只有一列unique_code CHAR(10) CHARSET ascii PRIMARY KEY