2013-10-07 40 views
4

我遇到了批量插入到MSSQLSRV 2008 R2臨時表中的問題。PHP有w/MS SQL批量插入緩慢

我插入的CSV大約200,000行,大約需要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使用PDO,但必須使用準備好的語句才能得到更多保護。 – bksi

+0

數據庫服務器與PHP服務器在同一網絡上運行嗎?你可能有帶寬問題? – MonkeyZeus

+0

您是否嘗試過對腳本進行基準測試,以查看減速是否實際上是INSERT? – MonkeyZeus

回答

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); 
+0

內存在我的機器上不是問題,但它也不會讓內存效率更高。我會試試看看是否有幫助。謝謝! – Gimli