2016-12-09 1 views
0

Ich habe eine Aufgabe zu üben. Generiere 5 Millionen Datensätze: string (15), string (15), int (min: 1 max: 99) und speichere sie in einer Datenbank postgresql. Meine erste Version des Skripts war die geschätzte Zeit für 5 Millionen: 16120 Sekunden.Generieren Sie 5 Millionen Datensätze und fügen Sie sie in fünf Sekunden in die Datenbank ein

EDIT (12. Dezember 15 um 11:50): Nach mehreren Optimierungen derzeit: 80 Sekunden.

Was muss ich ändern, um das gewünschte Ergebnis zu erzielen?

Im Folgenden präsentiere ich die am meisten optimierte Version des Codes.

// In Source Code -> function insertDataFive 

$countRecords = 5000000; 

for ($i = 0; $i < ($countRecords/100000); $i++) // $i < 50 
{ 
    echo "Loop one \$i: " . $i . "\n"; 
    try 
    { 
     echo "Memory used (before) real: " . (memory_get_peak_usage(true)/1024/1024) . " MiB\n"; 

     $sql = "INSERT INTO users 
    (first_name, last_name, user_age) 
    VALUES ('" . randomString(15) . "','" . randomString(15) . "'," . randomAge() . ")"; 

     for ($j = 1; $j < 100000; $j++) 
     { 
      $sql .= ",('" . randomString(15) . "','" . randomString(15) . "'," . randomAge() . ")"; 
     } 
     $dbh->exec($sql); 


     echo "Memory used (after) real: " . (memory_get_peak_usage(true)/1024/1024) . " MiB\n\n"; 
     unset($sql); 
    } catch (PDOException $e) 
    { 
     echo 'PDO error: ' . $e->getMessage(); 
    } 
} 

Vielleicht verwende ich Cloud etwas anderes als INSERT?

EDIT: Problem gelöst! 2016 Dez 19script relase 1.0 source

WICHTIG! bevor ausgeführt, sobald dieses Skript exec in cmd unten Befehl

mkdir/tmp/ram

mount -t tmpfs -o size = 512m tmpfs/tmp/ram

Daten erzeugen:

function createDataFile($task, $rows = 1250000) 
{ 
    try 
    { 
     global $fileName, $fileExtension, $timeFileCreate; 
     $startTime = microtime(true); 
     $fileCSV = $fileName . $task . $fileExtension; 
     $fileHandler = fopen('/tmp/ram/' . $fileCSV, 'w'); 
     if ($fileHandler != false) 
     { 
      if (DEBUG) 
      { 
       echo "Memory used (before) fwrite: " . getMemoryUsage() . " MiB\n"; 
      } 
      for ($i = ($task - 1) * $rows; $i < $task * $rows; $i++) 
      { 
       fwrite($fileHandler, (($i + 1 . "," 
         . generateRangomString(15) . "," 
         . generateRangomString(15) . "," 
         . generateRangomAge()) . "\n")); 
      } 
      fclose($fileHandler); 
      if (DEBUG) 
      { 
       echo "Memory used (after) fwrite: " . getMemoryUsage() . " MiB\n"; 
      } 
     } 
     else 
     { 
      echo "File open error"; 
     } 
     $timeFileCreate += (microtime(true) - $startTime); 
    } 
    catch (Exception $ex) 
    { 
     echo "File Error: " . $ex->getMessage(); 
    } 
} 

Zeilen einfügen:

function insertSingleDataFile($dbh, $task) 
{ 
    global $fileName, $fileExtension, $timeSqlBulk; 
    $startTime = microtime(true); 
    $fileCSV = $fileName . $task . $fileExtension; 
    $sqlBulk = "COPY users (user_id, first_name, last_name, user_age) 
    FROM '/tmp/ram/$fileCSV' 
    DELIMITER ','"; 

    try 
    { 
     $dbh->query($sqlBulk); 
    } 
    catch (PDOException $e) 
    { 
     echo 'PDO error: ' . $e->getMessage() . "\n\n"; 
    } 
    $timeSqlBulk += (microtime(true) - $startTime); 
} 
+3

Laden Daten infile und Hinzufügen von Indizes nach Inserts sind die Punkte der Verbesserung –

+0

5 Millionen Datensätze ?? ⊙▃⊙ – Blueblazer172

+5

Ich denke, diese Frage eignet sich besser für den Stackexchange von codereview, da es sich nicht um einen Fehler in Ihrem Code handelt, sondern um eine Optimierung. – KhorneHoly

Antwort

0

Sie tr könnte y alles in eine Schleife verschieben. Es besteht keine Notwendigkeit, zuerst die Aufzeichnungen zu sammeln, z.B.

$dbh->beginTransaction(); 

$sql = 'INSERT INTO users 
    (first_name, last_name, user_age) 
    VALUES (?, ?, ?)'; 

$sth = $dbh->prepare($sql); 

for ($i = 0; $i < $countRecords; $i++) { 
    $sth->execute(array(
     randomString(15), 
     randomString(15), 
     randomAge(), 
    )); 
} 

$dbh->commit(); 

diese Weise können Sie die zusätzlichen Speicher für eine große Auswahl und das Packen und Entpacken von einem assoziativen zu einem einfachen Array speichern.

+0

So ähnlich? [link] (https://gist.github.com/szczepix/0202625a2b624788d6ffd5ecd442dbf1) – szczepix

+0

Dies ist die gleiche Zeit - nichts ändern – szczepix

+0

Dann können wir Speicheranforderungen für das Array als Problem ausschließen, und einer der Vorschläge in den Kommentaren wie ' load data infile' oder 'pg_copy_from' könnte die Performance verbessern. –

Verwandte Themen