php pdo 一次插入太多行的有效方法
php pdo efficient way to insert too many rows at a time
我正在以编程方式将行从 excel 文件导入数据库。 excel 文件有 10 列 * 30000 行。我已将这些数据导入 php 数组,然后将其插入数据库。
上传文件后,需要 7-8 分钟才能将所有行插入数据库。我知道两种插入行的方法
第一种方法:
生成动态查询,例如
INSERT INTO table_name (col1, col2,..) VALUES (row1, row1, ....), (row2, row2, ....), (row3, row3, ....), (row4, row4, ....), ...
和运行插入所有行的查询。
第二种方法:
$con->prepare("INSERT INTO table_name (col1, col2, ...) VALUES (:col1, :col2, ...)");
foreach ($rows as $row) { // Loop through all rows and insert them
$result->bindParam(':col1', $val1);
$result->bindParam(':col2', $val2);
$result->bindParam(':col3', $val3);
...
...
$result->execute();
}
第一种方法看起来混乱且效率低下,我正在使用第二种方法,但它每秒仅插入 500-700 行,插入所有行需要 7-8 分钟的总时间。
还有哪些方法比这些方法更高效、更快速?
编辑:不建议将 excel 文件直接导入到 mysql。数据在插入数据库之前需要进行处理。
最快的方法是将数百个插入包装到事务和提交中。 MySQL 将使用硬盘驱动器的单个 input/output 操作来写入许多记录 - 这很快。
$con->prepare("INSERT INTO table_name (col1, col2, ...) VALUES (:col1, :col2, ...)");
$inserts = 1000;
$counter = 0;
foreach ($rows as $row) { // Loop through all rows and insert them
if($counter === 0 && !$con->inTransaction()) {
$con->beginTransaction();
}
$result->bindParam(':col1', $val1);
$result->bindParam(':col2', $val2);
$result->bindParam(':col3', $val3);
...
...
$result->execute();
$counter++;
if($counter === $inserts) {
$con->commit();
}
}
if($con->inTransaction()) {
$con->commit();
$counter = 0;
}
上面的代码应该在每执行 1000 次插入后提交。我还没有测试它,所以它很可能包含错误,但它的目的是说明如何在一个事务中包装 1000 个插入并提交它。
尝试将您的 SQL 包装成一个 TRANSACTION,最后提交您的数据。这将释放大量资源,因为提交数据会做很多事情(它告诉您的数据库保存您正在插入的数据和重新索引 - 假设您有它们)。
此外,请尝试确保您与数据库的连接已合并 - 这意味着您不会每次都从数据库中获取新连接,而是使用同一个连接。
不过,使用事务的风险在于,如果您的数据集中出现一个错误(阻止插入),它将回滚整个数据集。
像这样的东西可以工作..
<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true)); // POOLED
echo "Connected\n";
} catch (Exception $e) {
die("Unable to connect: " . $e->getMessage());
}
try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$dbh->prepare("INSERT INTO table_name (col1, col2, ...) VALUES (:col1, :col2, ...)");
foreach ($rows as $row) { // Loop through all rows and insert them
// I am not sure where you define $result
// Review in your implementation if you use
$result->bindParam(':col1', $val1);
$result->bindParam(':col2', $val2);
$result->bindParam(':col3', $val3);
...
...
$result->execute();
}
} catch (Exception $e) {
$dbh->rollBack();
echo "Failed: " . $e->getMessage();
}
$dbh->commit();
?>
我正在以编程方式将行从 excel 文件导入数据库。 excel 文件有 10 列 * 30000 行。我已将这些数据导入 php 数组,然后将其插入数据库。
上传文件后,需要 7-8 分钟才能将所有行插入数据库。我知道两种插入行的方法
第一种方法:
生成动态查询,例如
INSERT INTO table_name (col1, col2,..) VALUES (row1, row1, ....), (row2, row2, ....), (row3, row3, ....), (row4, row4, ....), ...
和运行插入所有行的查询。
第二种方法:
$con->prepare("INSERT INTO table_name (col1, col2, ...) VALUES (:col1, :col2, ...)");
foreach ($rows as $row) { // Loop through all rows and insert them
$result->bindParam(':col1', $val1);
$result->bindParam(':col2', $val2);
$result->bindParam(':col3', $val3);
...
...
$result->execute();
}
第一种方法看起来混乱且效率低下,我正在使用第二种方法,但它每秒仅插入 500-700 行,插入所有行需要 7-8 分钟的总时间。
还有哪些方法比这些方法更高效、更快速?
编辑:不建议将 excel 文件直接导入到 mysql。数据在插入数据库之前需要进行处理。
最快的方法是将数百个插入包装到事务和提交中。 MySQL 将使用硬盘驱动器的单个 input/output 操作来写入许多记录 - 这很快。
$con->prepare("INSERT INTO table_name (col1, col2, ...) VALUES (:col1, :col2, ...)");
$inserts = 1000;
$counter = 0;
foreach ($rows as $row) { // Loop through all rows and insert them
if($counter === 0 && !$con->inTransaction()) {
$con->beginTransaction();
}
$result->bindParam(':col1', $val1);
$result->bindParam(':col2', $val2);
$result->bindParam(':col3', $val3);
...
...
$result->execute();
$counter++;
if($counter === $inserts) {
$con->commit();
}
}
if($con->inTransaction()) {
$con->commit();
$counter = 0;
}
上面的代码应该在每执行 1000 次插入后提交。我还没有测试它,所以它很可能包含错误,但它的目的是说明如何在一个事务中包装 1000 个插入并提交它。
尝试将您的 SQL 包装成一个 TRANSACTION,最后提交您的数据。这将释放大量资源,因为提交数据会做很多事情(它告诉您的数据库保存您正在插入的数据和重新索引 - 假设您有它们)。
此外,请尝试确保您与数据库的连接已合并 - 这意味着您不会每次都从数据库中获取新连接,而是使用同一个连接。
不过,使用事务的风险在于,如果您的数据集中出现一个错误(阻止插入),它将回滚整个数据集。
像这样的东西可以工作..
<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true)); // POOLED
echo "Connected\n";
} catch (Exception $e) {
die("Unable to connect: " . $e->getMessage());
}
try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$dbh->prepare("INSERT INTO table_name (col1, col2, ...) VALUES (:col1, :col2, ...)");
foreach ($rows as $row) { // Loop through all rows and insert them
// I am not sure where you define $result
// Review in your implementation if you use
$result->bindParam(':col1', $val1);
$result->bindParam(':col2', $val2);
$result->bindParam(':col3', $val3);
...
...
$result->execute();
}
} catch (Exception $e) {
$dbh->rollBack();
echo "Failed: " . $e->getMessage();
}
$dbh->commit();
?>