mysql – PHP PDO使用bindParam插入多个(10000)相同的行.好的做法?

我需要能够一次从表单请求中插入10,000个类似的行.目前我已经完成了一行准备语句循环10’000次,其中我重新绑定每个var的变量.

for ($i=0; $i < intval($cloneCount); $i++) 
{
    ... 9 other bindParam
    $insertG->bindParam(':v1', $v1, PDO::PARAM_STR);
    $insertG->bindParam(':v2', $v2, PDO::PARAM_INT);
    $insertG->execute();
}

它需要将近30秒才能实现,当然不是一个好习惯.它今天是10’000但明天可能是100’000.

如果我在一个查询中插入多行与(v1,v2),(v1,v2)…我需要将每个值绑定到一个新的参数,因此我相信我需要在一个查询中有近100’000 bindedParam.如果它是UTF-8并且我计算每个字符大约2个字节(我知道它可以达到4个)我的查询将大约10到20 MB并且mysql服务器在另一台机器上.说这话我很惊讶我的设计要求不好只需要30秒才能成功.

有没有办法只发送一行并告诉mysql服务器复制最后一行10’000次?

编辑部分解决方案

继Bill Karwin和Zsolt Szilagy建议之后.我设法通过以下调整到达远程mysql服务器的10’000插入到5-6秒:

$dataBase->beginTransaction();

$insertG = $dataBase->prepare('INSERT INTO G...)
...
10 * bindParam of all kinds

for ($i=0; $i < 10000; ++$i) 
{ 
    $hashKey = sha1(uniqid().$i); //$hashKey is a binded param
    $insertG->execute();
}
$dataBase->commit();
最佳答案
在循环的每次迭代期间,您不需要bindParam(). bindParam()导致变量$v1,$v2等被引用绑定,因此您需要做的就是更改这些变量的值,然后重新执行查询.这可以减少开销.

此外,您可以避免每次循环调用intval().只需确保$cloneCount在循环之前被强制转换为整数一次.这是一个非常小的改进,但这是一个很好的做法.

$cloneCount = (int) $cloneCount;

... 9 other bindParam
$insertG->bindParam(':v1', $v1, PDO::PARAM_STR);
$insertG->bindParam(':v2', $v2, PDO::PARAM_INT);

for ($i=0; $i < $cloneCount; $i++) 
{
  $v1 = /* something */
  $v2 = /* something */
  $insertG->execute();
}

您还应该避免自动提交.将MySQL语句执行的事务开销减少starting an explicit transaction,插入数千行,然后提交事务.

但是,将数千个类似行的批量INSERT加速到单个表的最佳方法是使用LOAD DATA LOCAL INFILE而不是INSERT.即使您使用参数,事务,多行插入以及您可以想到的任何其他技巧,它也会比逐行INSERT快10-20倍.

即使您必须使用PHP将数据写入.CSV文件到磁盘,然后在该文件上使用LOAD DATA LOCAL INFILE,它仍然要快得多.

有关更多提示,另请参阅MySQL手册中的Speed of INSERT Statements.

转载注明原文:mysql – PHP PDO使用bindParam插入多个(10000)相同的行.好的做法? - 代码日志