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

标签 mysql sql insert indexing

MySQL Docs说:

假设 B 树索引,表的大小减慢了 log 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 - 删除索引

我读到在插入之前删除索引可能有助于提高插入速度。插入后,我再次添加索引。但是这里唯一的索引是主键,在我看来删除它不会有太大帮助。此外,虽然主键被丢弃,但所有选择查询都将非常缓慢。

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

编辑:以下是一些关于在具有约 147 万行的表中插入约 60,000 行的测试:

使用上面描述的普通查询: 146 秒

使用 MySQL 的 LOAD DATA infile : 145 秒

使用 MySQL 的 LOAD DATA infile 并按照 David Jashi 在他的回答中的建议拆分 csv 文件:60 个文件每个 1000 行需要 136 秒,6 个文件每个 10,000 行需要 136 秒 p>

删除并重新添加主键:删除键耗时 11 秒,插入数据耗时 0.8 秒,但重新添加主键耗时 153 秒,总共耗时约 165 秒

最佳答案

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

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

Here's a great read about configuring InnoDB

在那之后,您需要知道一件事——那就是数据库如何在内部完成它们的工作,硬盘是如何工作的等等。我将在下面的描述中简化机制:

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

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

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

Percona 的家伙在相对便宜的硬件上实现了每秒 15k 的插入。即使每秒插入 5k 也不错。像你这样的表很小,我已经在一个类似的表(3 列以上)上进行了测试,我使用 16GB 内存机器和 240GB SSD(1 个驱动器,没有 RAID,用于测试目的)。

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

关于MySQL 优化 INSERT 速度因索引而变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16977898/

相关文章:

mysql - 有什么办法可以优化这个mysql查询吗?

sql-server - SQL Server : want to insert data into one column, rest nulls: 不让我

php - MySQL PHP - 正斜杠后缺少字符

php - Laravel 插入一对多关系

c# - MySql.Data.dll 中发生类型 'System.InvalidOperationException' 的未处理异常

mysql - 在单个查询中按值获取行数

c# - string.insert 多个值。这可能吗?

mysql - 如何获取下面提到的条件下的数据?

sql - 我怎样才能快速删除 postgres 中的行?

sql - MySQL "between"子句不包含?