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


当前回答

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

SET FOREIGN_KEY_CHECKS=0;

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

SET FOREIGN_KEY_CHECKS=1;

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

其他回答

下面是我做的一个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倍

我只是做了一个小的基准测试,似乎对于很多行它不是更快。这里是我插入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是最好的选择。

当涉及到插入时,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一样有内部延迟。

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

SET FOREIGN_KEY_CHECKS=0;

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

SET FOREIGN_KEY_CHECKS=1;

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

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