4

我在 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...
...

我一直在互联网上寻找可能的解决方案,但找不到任何可行的方法。

我发现这篇文章基本上说要一起批处理行(我已经完成了)。

我发现另一篇关于 PDO 的帖子,设置 connectionpooling=0。我试过了,并没有看到性能有任何提高。

有没有其他人遇到过 SQLSRV 和 PHP 的这个问题?

干杯,

4

1 回答 1

1

我有一个类似的问题。因为我的问题是可用内存不足,所以我的服务器不得不花费额外的时间来处理虚拟内存。如果这不是你的问题,我的回答对你没有用。

您正在使用字符串连接,然后使用 substr 删除最后一个逗号。当您使用 substr 时,它会生成另一个字符串副本,这对于长字符串来说是内存密集型的。有关字符串很长时会发生什么的示例,请参阅此问题。当我切换到数组串联时,由于内存使用量较低,我的速度大大提高。但是,如果您没有内存问题,那么数组串联实际上对您来说可能会更慢

我看到的其他几件事是您只需要收集一次 $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);
于 2013-10-07T22:26:11.153 回答