我试图优化我的代码插入数据到MySQL的一部分。我应该链插入,使一个巨大的多行插入或多个单独的插入更快?
当前回答
MYSQL 5.5 一条sql insert语句需要300到450毫秒。 而下面的stats是内联多个insert语句。
(25492 row(s) affected)
Execution Time : 00:00:03:343
Transfer Time : 00:00:00:000
Total Time : 00:00:03:343
我想说内联是一种方式:)
其他回答
通常,由于连接开销,多个插入会更慢。一次执行多个插入将减少每次插入的开销。
根据您使用的语言,您可以在访问db并将每个插入添加到批处理之前,使用编程/脚本语言创建一个批处理。然后,您将能够使用一个连接操作执行大型批处理。这是Java中的一个例子。
下面是我做的一个PHP小测试的结果:
我试图在3种不同的方式插入3000条记录,使用PHP 8.0, MySQL 8.1 (mysqli)
多个插入查询,包含多个事务:
$start = microtime(true);
for($i = 0; $i < 3000; $i++)
{
mysqli_query($res, "insert into app__debuglog VALUE (null,now(), 'msg : $i','callstack','user','debug_speed','vars')");
}
$end = microtime(true);
echo "Took " . ($end - $start) . " s\n";
完成5次,平均11.132秒(+/- 0.6秒)
多个插入查询,一个事务:
$start = microtime(true);
mysqli_begin_transaction($res, MYSQLI_TRANS_START_READ_WRITE);
for($i = 0; $i < 3000; $i++)
{
mysqli_query($res, "insert into app__debuglog VALUE (null,now(), 'msg : $i','callstack','user','debug_speed','vars')");
}
mysqli_commit($res);
$end = microtime(true);
echo "Took " . ($end - $start) . " ms\n";
5次测试的结果:0.48s (+/- 0.04s)
单个聚合插入查询
$start = microtime(true);
$values = "";
for($i = 0; $i < 3000; $i++)
{
$values .= "(null,now(), 'msg : $i','callstack','user','debug_speed','vars')";
if($i !== 2999)
$values .= ",";
}
mysqli_query($res, "insert into app__debuglog VALUES $values");
$end = microtime(true);
echo "Took " . ($end - $start) . " ms\n";
5次测试的结果:0.085s (+/- 0.05s)
因此,对于3000行插入,看起来像:
在单个写事务中使用多个查询比在每个插入中使用多个事务进行多个查询快22倍。 使用单个聚合插入语句仍然比使用单个写事务的多个查询快6倍
我知道我在回答这个问题几乎两年半之后才回答这个问题,但我只是想提供一些来自我现在正在从事的项目的硬数据,这些数据表明,在每个插入中执行多个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的值)。
当涉及到插入时,Mysql和MariaDB的优化是多么糟糕,这是荒谬的。 我测试了mysql 5.7和mariadb 10.3,没有真正的区别。
我已经在一台带有NVME磁盘、70000 IOPS、1.1 GB/sec seq吞吐量的服务器上进行了测试,这可能是全双工(读和写)。 该服务器也是高性能服务器。 给了它20gb的内存。 数据库完全为空。
在做多行插入时,我收到的速度是每秒5000个插入(尝试了1MB到10MB的数据块)
现在是线索: 如果我添加另一个线程并插入到相同的表中,我突然有2x5000 /秒。 再多一个线程,我就有15000个线程了
考虑一下:当执行一个线程插入时,这意味着您可以按顺序写入磁盘(索引除外)。 当使用线程时,你实际上降低了可能的性能,因为它现在需要做更多的随机访问。 但事实证明,mysql的优化非常糟糕,线程的帮助很大。
这种服务器的实际性能可能是每秒数百万,CPU空闲,磁盘空闲。 原因很明显,mariadb和mysql一样有内部延迟。
在同一时间通过导线发送尽可能多的插入。实际的插入速度应该是相同的,但是您将从网络开销的减少中看到性能的提高。