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语句相比,这要快得多(在某些情况下要快很多倍).
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_packet的值.)
Mar*_*rkR 17
一个主要因素是您是否使用事务引擎以及是否自动提交.
默认情况下,自动提交已启用,您可能希望将其保留; 因此,您执行的每个插入都会执行自己的事务.这意味着如果每行执行一次插入,那么您将为每一行提交一个事务.
假设有一个线程,这意味着服务器需要将一些数据同步到光盘中.它需要等待数据到达持久存储位置(希望RAID控制器中的电池支持的RAM).这本质上相当缓慢,可能会成为这些情况的限制因素.
我当然假设您正在使用事务引擎(通常是innodb)并且您没有调整设置以降低持久性.
我还假设您使用单个线程来执行这些插入.使用多个线程会使事情变得混乱,因为某些版本的MySQL在innodb中具有工作组提交 - 这意味着执行自己提交的多个线程可以共享对事务日志的单个写入,这很好,因为这意味着与持久存储的同步更少.
另一方面,结果是,您真的想要使用多行插入.
它有一个限制,它会适得其反,但在大多数情况下它至少有10,000行.因此,如果您将它们分批最多1,000行,那么您可能很安全.
如果你正在使用MyISAM,还有其他一些东西,但我不会厌倦你.和平.
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 行插入,看起来像:
通常,对数据库的调用次数越少越好(意味着更快,更有效),因此尝试以最小化数据库访问的方式对插入进行编码.请记住,除非您使用连接池,否则每个数据库访问都必须创建连接,执行sql,然后拆除连接.相当多的开销!
小智 5
我刚刚做了一个小的基准测试,看来对于很多行来说它并没有更快。这是我插入 280 000 行的结果:
看来1000乘1000是最好的选择。
| 归档时间: |
|
| 查看次数: |
90398 次 |
| 最近记录: |