MySQL优化INSERT速度因索引而减慢

时间:2013-06-07 06:47:44

标签: mysql sql insert indexing

MySQL Docs说:

假设B树索引,表的大小会减慢日志N的索引插入速度。

这是否意味着插入每个新行时,插入速度将减慢因子log N,其中N,我假设是行数?即使我只在一个查询中插入所有行?即:

INSERT INTO mytable VALUES (1,1,1), (2,2,2),  (3,3,3), .... ,(n,n,n)

其中n为~70,000

我目前在表中有大约147万行,结构如下:

CREATE TABLE mytable (
   `id` INT,
   `value` MEDIUMINT(5),
   `date` DATE,
   PRIMARY_KEY(`id`,`date`)
) ENGINE = InnoDB

当我在事务中以上述方式插入时,提交时间约为275秒。如何优化这一点,因为每天都要添加新数据,插入时间将继续减慢。

此外,除了可能有帮助的查询之外还有什么吗?也许一些配置设置?

可能的方法1 - 删除指数

我读到在插入之前删除索引可能有助于插入速度。插入后,我再次添加索引。但是这里唯一的索引是主键,在我看来放弃它对我来说没什么用。此外,虽然主键是已删除,但所有选择查询都会变慢。

我不知道任何其他可能的方法。

编辑:以下是一些关于在表格中插入~60,000行的测试,其中包含~1.47 mil行:

使用上述简单查询: 146秒

使用MySQL的LOAD DATA infile: 145秒

使用MySQL的LOAD DATA infile并按照David Jashi的回答拆分csv文件: 136个文件,60个文件,每个1000行,6个文件136秒,每个10,000行

删除并重新添加主键:键删除需要11秒,插入数据需要0.8秒,重新添加主键需要153秒,完全需要~165秒

5 个答案:

答案 0 :(得分:18)

如果您想要快速插入,首先需要的是适当的硬件。这假设有足够的RAM,SSD而不是机械驱动器和相当强大的CPU。

由于你使用InnoDB,你想要的是优化它,因为默认配置是为慢速和旧机器设计的。

Here's a great read about configuring InnoDB

之后,您需要了解一件事 - 这就是数据库在内部执行操作的方式,硬盘驱动器的工作方式等等。我将在以下描述中简化机制:

一个事务是MySQL等待硬盘确认它写入了数据。这就是机械驱动器上交易速度慢的原因,它们每秒可以进行200-400次输入输出操作。翻译,这意味着您可以在机械驱动器上使用InnoDB每秒获得200次插入查询。当然,这是简化的解释,只是为了概述正在发生的事情,它不是交易背后的完整机制

由于查询(尤其是与表大小相对应的查询)在字节方面相对较小 - 因此您实际上会在单个查询上浪费宝贵的IOPS。

如果你在一个事务中包装多个查询(100或200或更多,没有确切的数字,你必须测试),然后提交它 - 你将立即实现每秒更多的写入。

Percona家伙在相对便宜的硬件上实现了15k插入一秒钟。即使是5k插入一秒也不错。像你这样的表很小,我在类似的表上做了测试(3列以上),我设法得到10亿条记录没有明显的问题,使用16GB RAM机器和240GB SSD(1个驱动器,没有RAID,用于测试目的)。

TL; DR: - 按照上面的链接,配置您的服务器,获取SSD,在1个事务中包含多个插入并获利。并且不要关闭索引然后打开它,它总是不适用,因为在某些时候你将花费处理和IO时间来构建它们。

答案 1 :(得分:4)

无论如何,删除索引肯定会有所帮助。另请考虑使用LOAD DATA。您可以找到一些比较和基准here

此外,在构造PRIMARY KEY时,请按顺序使用表中第一个字段,即在结构中切换第二个和第三个字段的位置。

答案 2 :(得分:3)

如果您正在进行一百万行的批量插入,那么删除索引,执行插入以及重建索引可能会更快。但是,如果您的问题是单行插入花费的时间太长,那么您还有其他问题(例如内存不足),并且删除索引也无济于事。

答案 3 :(得分:1)

建立/重建索引是您要加速的目标。如果您必须具有此表/密钥结构,更快的硬件和/或调整服务器配置以加快索引构建可能是答案 - 确保您的服务器和设置可以在内存中完成。

否则,考虑使用可提高插入速度的结构进行权衡。或者,想想你可以快乐地生活3分钟插入的方式。

答案 4 :(得分:0)

在某些情况下,我发现以中等大小的块插入事务会有所帮助,因为有时似乎允许进行一些批量操作。在其他情况下,这可能是由于锁定和事务开销而使事情变慢了。