我遇到批量插入MSSQLSRV 2008 R2中的临时表的问题。
我正在插入一个包含约200,000行的CSV,大约需要5分钟才能完成。
我尝试使用PDO和sqlsrv驱动程序。他们似乎都表现不佳。
以下是用于了解我正在做什么的代码(我包括SQLSRV和PDO代码):
...
try {
//create structure table record
foreach ($mapped_data as $k => $v) {
$insert .= $k . ",";
$values .= $v . ",";
}
$insert = substr($insert, 0, -1); //remove last ,
$values = substr($values, 0, -1);
$tableName = $table;
if ($stageData) {
$tableName = "stage_$table";
}
if ( $query == "" )
$query = "INSERT INTO $tableName ($insert) VALUES ";
$query .= "($values),";
// Insert in blocks of 1000 lines
if ($line % 1000 == 0) {
$log->logInfo("Executing @ line: $line");
$query = substr($query, 0, -1); //remove last ,
$query .= ";";
// ======================
// = SQLSRV DRIVER CODE =
// ======================
sqlsrv_begin_transaction($sqlsrvConn);
$queryResult = sqlsrv_query($sqlsrvConn,$query);
if ($queryResult) {
sqlsrv_commit($sqlsrvConn);
} else {
sqlsrv_rollback($sqlsrvConn);
}
// ===================
// = PDO DRIVER CODE =
// ===================
$conn->beginTransaction();
$res = $conn->prepare($query);
if($res->execute() === false) {
$errInfo = $res->errorInfo();
if ( $conn->inTransaction() ) {
$conn->rollback();
}
$log->logInfo('Data importing error on line: ' . $line . $errInfo[2]);
$errors[] = 'Data importing error on line: ' . $line . $errInfo[2];
} else {
if ( $conn->inTransaction() ) {
$conn->commit();
$query = "";
$importedRows += ($line - 6) - $importedRows;
}
}
}
}
catch (PDOException $e) {
if ( $conn->inTransaction() ) {
$conn->rollBack();
}
$log->logInfo('PDO Exception: ' . $e->getMessage());
$errors[] = 'PDO Exception: ' . $e->getMessage();
}
$line++;
} // End of while loop through each CSV Line
fclose($handle);
$totalRows = $line - 6;
$importedRows += $totalRows - $importedRows;
// Insert remaing queries afterwards...
...
我一直在寻找可能的解决方案,但一直没有找到任何有效的解决方案。
我发现this post基本上说要将行批处理(我已经完成了)。
我发现另一个帖子说PDO,设置connectionpooling = 0。我试过了,并没有看到任何性能提升。
有没有其他人使用SQLSRV和PHP遇到此问题?
干杯,
答案 0 :(得分:1)
我有一个类似的问题。因为我的问题是缺少可用内存,所以我的服务器不得不花费额外的时间来处理虚拟内存。如果这不是你的问题,我的回答对你没用。
您正在使用字符串连接,后跟substr删除最后一个逗号。当您使用substr时,它会生成该字符串的另一个副本,这对于长字符串来说是内存密集型的。有关字符串很长时会发生什么的示例,请参阅this question。当我切换到阵列连接时,由于内存使用率较低,我的速度大大提高。但是,如果您没有内存问题,阵列连接实际上可能是slower。
我看到的其他一些事情是你只需要收集一次$ inserts变量,并且一旦你不再需要它们就不会取消大变量。我不知道纠正这种事情是否会对你产生明显的影响。以下是您可以尝试的基本类型的更改:
if(!isset($insert)) {
$insert = array();
$collect = true;
}
$values = $array();
foreach ($mapped_data as $k => $v) {
if(isset($collect))
$insert[] = $k;
$values[] = $v;
}
unset($collect);
.....
if(!isset($queryend))
$queryend = array();
$queryend[] = "(".implode(",",$values).")";
.....
$query = "INSERT INTO $tableName ("
.implode(",",$insert)
.") VALUES "
.implode(",", $queryend);
unset($queryend); //always unset big things as soon as possible
..... //after $res = $conn->prepare($query);
unset($query);