PHP w / MS SQL lent sur l'encart en vrac

J'ai un problème avec l'insertion en bloc dans une table de transfert dans MSSQLSRV 2008 R2.

J'insère un file CSV avec environ 200 000 lignes et cela prend environ 5 minutes.

J'ai essayé d'utiliser à la fois PDO et le pilote sqlsrv. Ils semblent tous les deux donner des performances médiocres.

Voici le code pour donner une idée de ce que je fais (j'ai inclus le code SQLSRV et 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... ... 

J'ai parcouru Internet à la search de solutions possibles, mais je n'ai pas réussi à find quelque chose qui fonctionne.

J'ai trouvé ce post qui dit essentiellement de lignes de lot set (que j'ai déjà fait).

Et j'ai trouvé un autre post qui disait pour PDO, pour définir connectionpooling = 0. J'ai essayé cela et je n'ai vu aucune augmentation de performance.

Est-ce que quelqu'un d'autre a rencontré ce problème avec SQLSRV et PHP?

À votre santé,

J'ai eu un problème similaire. Parce que mon problème était un manque de memory disponible, mon server a dû prendre plus de time pour gérer la memory virtuelle. Si ce n'est pas votre problème, ma réponse ne vous sera pas utile.

Vous utilisez la concaténation de strings suivie de substr pour supprimer la dernière virgule. Lorsque vous utilisez substr, il crée une autre copy de la string, qui nécessite beaucoup de memory pour les longues strings. Voir cette question pour un exemple de ce qui se passe quand les strings sont longues. Quand je suis passé à la concaténation de tableau, ma vitesse a considérablement augmenté en raison de l'utilisation de la memory inférieure. Cependant, si vous n'avez pas de problèmes de memory, la concaténation du tableau peut être plus lente pour vous.

Quelques autres choses que j'ai vues étaient que vous avez seulement besoin de collecter la variable $ inserts une fois, et vous n'écartez pas les grosses variables dès que vous n'en avez plus besoin. Je ne sais pas si corriger pour ce genre de chose fera une différence appréciable pour vous ou non. Voici les types de modifications de base que vous pourriez essayer:

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