我需要能够一次从表单请求中插入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();
此外,您可以避免每次循环调用intval().只需确保$cloneCount在循环之前被强制转换为整数一次.这是一个非常小的改进,但这是一个很好的做法.
$cloneCount = (int) $cloneCount;
... 9 other bindParam
$insertG->bindParam(':v1',PDO::PARAM_STR);
$insertG->bindParam(':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.