我试图优化我的代码插入数据到MySQL的一部分。我应该链插入,使一个巨大的多行插入或多个单独的插入更快?


当前回答

我知道我在回答这个问题几乎两年半之后才回答这个问题,但我只是想提供一些来自我现在正在从事的项目的硬数据,这些数据表明,在每个插入中执行多个VALUE块确实比连续的单个VALUE块insert语句快得多。

The code I wrote for this benchmark in C# uses ODBC to read data into memory from an MSSQL data source (~19,000 rows, all are read before any writing commences), and the MySql .NET connector (Mysql.Data.*) stuff to INSERT the data from memory into a table on a MySQL server via prepared statements. It was written in such a way as to allow me to dynamically adjust the number of VALUE blocks per prepared INSERT (ie, insert n rows at a time, where I could adjust the value of n before a run.) I also ran the test multiple times for each n.

做单个VALUE块(例如,一次一行)需要5.7 - 5.9秒的时间。其他取值如下:

一次两行:3.5 - 3.5秒 一次排5行:2.2 - 2.2秒 一次10行:1.7 - 1.7秒 一次50行:1.17 - 1.18秒 一次100行:1.1 - 1.4秒 一次500行:1.1 - 1.2秒 一次1000行:1.17 - 1.17秒

所以,是的,即使只是将2或3个写入捆绑在一起,也可以显著提高速度(运行时减少了n倍),直到达到n = 5和n = 10之间的某个位置,此时改进显著下降,而在n = 10到n = 50范围内的某个位置,改进几乎可以忽略不计。

希望这有助于人们决定(a)是否使用multiprepare思想,(b)每个语句创建多少VALUE块(假设你想要处理的数据可能足够大,以推动查询超过MySQL的最大查询大小,我相信在很多地方默认是16MB,可能更大或更小,这取决于服务器上设置的max_allowed_packet的值)。

其他回答

一般来说,对数据库的调用次数越少越好(意味着更快、更高效),所以尽量以最小化数据库访问的方式编写插入代码。记住,除非使用连接池,否则每次数据库访问都必须创建一个连接,执行sql语句,然后断开连接。相当多的开销!

通常,由于连接开销,多个插入会更慢。一次执行多个插入将减少每次插入的开销。

根据您使用的语言,您可以在访问db并将每个插入添加到批处理之前,使用编程/脚本语言创建一个批处理。然后,您将能够使用一个连接操作执行大型批处理。这是Java中的一个例子。

https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html

插入一行所需的时间由以下因素决定,其中数字表示大致的比例: 连接:(3) 向服务器发送查询:(2) 解析查询:(2) 插入行:(1 ×行大小) 插入索引:(1 ×索引个数) 关闭:(1)

由此可见,发送一个大语句将为每个插入语句节省7的开销,进一步阅读文本还说:

如果同时插入来自同一客户端的多行,请使用带有多个VALUES列表的INSERT语句一次插入几行。这比使用单独的单行INSERT语句快得多(在某些情况下快很多倍)。

我只是做了一个小的基准测试,似乎对于很多行它不是更快。这里是我插入28000行的结果:

比10000:164.96秒 到5000分37秒 到1000时:12.56秒 到600秒:12.59秒 比500:13.81秒 到250秒:17.96秒 到400时:14.75秒 差100分27秒

看来1000 * 1000是最好的选择。

多次插入更快,但它有线程。另一个危险是禁用约束检查临时使插入快得多。你的桌子有没有它并不重要。例如,测试禁用外键,享受速度:

SET FOREIGN_KEY_CHECKS=0;

当然,你应该在插入后重新打开它:

SET FOREIGN_KEY_CHECKS=1;

这是插入大数据的常用方法。 数据完整性可能会被破坏,所以在禁用外键检查之前应该注意这一点。