哪个更快:多个单个INSERT还是一个多行INSERT?

dus*_*oft 174 mysql benchmarking insert

我正在尝试优化将数据插入MySQL的代码的一部分.我应该链接INSERT来制作一个巨大的多行INSERT还是更快的多个单独的INSERT?

mba*_*hau 271

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

插入行所需的时间由以下因素决定,其中数字表示大致比例:

  • 连接:(3)
  • 向服务器发送查询:(2)
  • 解析查询:(2)
  • 插入行:(1×行的大小)
  • 插入索引:(1×索引数)
  • 结束:(1)

从这一点可以看出,发送一个大型语句将为每个插入语句节省7个开销,在进一步阅读文本时也会说:

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

  • 如果多个单个INSERT在同一个数据库事务中,这个答案如何应用? (23认同)
  • @Pinch在执行~1.5k upserts(插入/更新)时使用事务将操作时间从约1.5秒减少到约0.2秒.或者换句话说,与单排插入相比,它的速度提高了86%.该死的. (9认同)
  • 我可以使用单个插入语句一次插入多少行。它允许我一次插入 10000 行吗? (2认同)
  • 注意:在MSSQL中似乎有很大不同:http://stackoverflow.com/questions/8635818/multiple-insert-statements-vs-single-insert-with-multiple-values (2认同)

Jon*_*ske 147

我知道我在回答这个问题之前有人问近两年半年后,但我只是想现在这表明,的确做多值块每个刀片是提供从项目我工作的一些硬数据MUCH比顺序单个VALUE块INSERT语句更快.

我在C#中为此基准编写的代码使用ODBC从MSSQL数据源(约19,000行,在开始任何写入之前读取所有内容)将数据读入内存,并将MySql .NET连接器(Mysql.Data.*)填充到通过预处理语句将数据从内存插入MySQL服务器上的表中.它的编写方式允许我动态调整每个准备好的INSERT的VALUE块的数量(即,一次插入n行,我可以在运行之前调整n的值.)我也运行了测试每个n多次.

单个VALUE块(例如,一次一行)需要5.7 - 5.9秒才能运行.其他值如下:

一次2行: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)是否使用多准备创意,以及(b)每个语句创建多少个VALUE块(假设您希望使用可能足够大的数据来推动查询超过最大查询大小对于MySQL,我认为在很多地方默认为16MB,可能更大或更小,具体取决于服务器上设置的max_allowed_pa​​cket的值.)

  • 总计秒数 - 每行的秒数除以~19,000行.虽然这是一个很小的数字,但如果您正在寻找一个容易比较的数字,那么行/秒可能是一个更好的指标. (3认同)

Mar*_*rkR 17

一个主要因素是您是否使用事务引擎以及是否自动提交.

默认情况下,自动提交已启用,您可能希望将其保留; 因此,您执行的每个插入都会执行自己的事务.这意味着如果每行执行一次插入,那么您将为每一行提交一个事务.

假设有一个线程,这意味着服务器需要将一些数据同步到光盘中.它需要等待数据到达持久存储位置(希望RAID控制器中的电池支持的RAM).这本质上相当缓慢,可能会成为这些情况的限制因素.

我当然假设您正在使用事务引擎(通常是innodb)并且您没有调整设置以降低持久性.

我还假设您使用单个线程来执行这些插入.使用多个线程会使事情变得混乱,因为某些版本的MySQL在innodb中具有工作组提交 - 这意味着执行自己提交的多个线程可以共享对事务日志的单个写入,这很好,因为这意味着与持久存储的同步更少.

另一方面,结果是,您真的想要使用多行插入.

它有一个限制,它会适得其反,但在大多数情况下它至少有10,000行.因此,如果您将它们分批最多1,000行,那么您可能很安全.

如果你正在使用MyISAM,还有其他一些东西,但我不会厌倦你.和平.

  • 你知道在**使用事务**时批量MySQL插入是否有任何意义。我只是想知道如果我的底层库(Java JDBC - mysql-connector-java-5.1.30)在我告诉它之前没有真正提交,我是否可以省去必须生成多值 SQL 命令的麻烦。 (3认同)

Jer*_*kar 15

以下是我做的一个小型 PHP 工作台的结果:

我尝试使用 PHP 8.0、MySQL 8.1 (mysqli) 以 3 种不同的方式插入 3000 条记录

多个插入查询,具有多个事务:

$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";
Run Code Online (Sandbox Code Playgroud)

做了 5 次,平均:11.132s (+/- 0.6s)

多个插入查询,单个事务:

$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";
Run Code Online (Sandbox Code Playgroud)

5 次测试的结果:0.48 秒(+/- 0.04 秒)

单个聚合插入查询

$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";
Run Code Online (Sandbox Code Playgroud)

5 次测试的结果:0.085 秒(+/- 0.05 秒)

因此,对于 3000 行插入,看起来像:

  • 在单个写入事务中使用多个查询比为每个插入使用多个事务进行多个查询快约 22 倍。
  • 使用单个聚合插入语句仍然比使用单个写入事务的多个查询快约 6 倍

  • 对大量事务使用 .= 时要小心,因为随着字符串变大,字符串连接速度会减慢(呈指数级?)。我已经看到这掩盖了性能,因此看起来单个事务实际上更快,但事实并非如此。我在事务数组上使用 implode() 作为插入查询的一部分。例如,“插入 tableA (fielda,fieldb) 值”。内爆(“,”,arrayInsert)。“在重复的键上......” (4认同)

RC.*_*RC. 8

尽可能多次在线上发送多个插入.实际的插入速度应该相同,但是您将看到网络开销减少带来的性能提升.


enn*_*ler 7

通常,对数据库的调用次数越少越好(意味着更快,更有效),因此尝试以最小化数据库访问的方式对插入进行编码.请记住,除非您使用连接池,否则每个数据库访问都必须创建连接,执行sql,然后拆除连接.相当多的开销!

  • 还有开销.如果您正在进行数千次插入,那么单独的运输时间(往返于每个单独的插入物)将很快被察觉. (6认同)

小智 5

我刚刚做了一个小的基准测试,看来对于很多行来说它并没有更快。这是我插入 280 000 行的结果:

  • 通过 10 000 : 164.96 秒
  • 到 5 000 : 37 秒
  • 按 1000 计算:12.56 秒
  • 600 : 12.59 秒
  • 500 秒:13.81 秒
  • 250 : 17.96 秒
  • 400 : 14.75 秒
  • 增加 100 : 27 秒

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