PHP-Datei Schreiben (fwrite / file_put_contents) Geschwindigkeit/Optimierung

So, ich habe eine Datenbank mit big data. Die Daten zu verwenden, liegt derzeit bei rund 2,6 GB.

Alle Daten, die geschrieben werden müssen, um eine Textdatei für die spätere Verwendung in anderen Skripts.

Der Daten wird pro Datei beschränkt und gesplittet in mehrere Teile. 100 Ergebnisse pro Datei (etwa 37MB jede Datei). Das ist ungefähr 71-Dateien.

Die Daten json-Daten, die serialisiert wird, und dann die Verschlüsselung mit openssl.

Werden die Daten korrekt in die Dateien geschrieben, bis die max execution time erreicht wird nach 240 Sekunden. Das ist nach über 20 Dateien…

Gut, ich kann nur verlängern, die Zeit, aber das ist nicht das problem.

Das problem ist Folgendes:

Writing file 1-6:   +/- 5 seconds
Writing file 7-8:   +/- 7 seconds
Writing file 9-11:  +/- 12 seconds
Writing file 12-14: +/- 17 seconds
Writing file 14-16: +/- 20 seconds
Writing file 16-18: +/- 23 seconds
Writing file 19-20: +/- 27 seconds

Note: time is needed time per file

In anderen Worten, mit jeder Datei im schreiben, das schreiben Zeit pro Datei geht deutlich nach oben, was bewirkt, dass das Skript zu langsam sein offcourse.

Die Struktur des Skripts ist ein bisschen wie diese:

$needed_files = count needed files/parts

for ($part=1; $part<=$needed_files; $part++) { //Loop throught parts
    $query > mysqli select data
    $data > json_encode > serialize > openssl_encrypyt
    file_put_contents($filename.$part, $data, LOCK_EX);
}

FUNKTIONIERENDEN CODE NACH HILFE

$notchDetails = mysqli_query($conn, "SELECT * FROM notches WHERE projectid = ".$projectid."");

$rec_count = 0;
$limit = 100;
$part = 1;

while ($notch = mysqli_fetch_assoc($notchDetails)) {

    $data1[] = $notch;
    $rec_count++;

    if ($rec_count >= $limit) {

        $data = json_encode($data1);
        $data = openssl_encrypt(bin2hex($data), "aes128", $pass, false, $iv);
        $filename = $mainfolder."/".$projectfolder."/".$subfolder."/".$fname.".part".$part."".$fext;
        file_put_contents($filename, $data, LOCK_EX);

        $part++;
        $rec_count = 0;
        $data = $data1 = "";

    }

}
if ($data1 != "") {
    $data = json_encode($data1);
    $data = openssl_encrypt(bin2hex($data), "aes128", $pass, false, $iv);
    $filename = $mainfolder."/".$projectfolder."/".$subfolder."/".$fname.".part".$part."".$fext;
    file_put_contents($filename, $data, LOCK_EX);
}

mysqli_free_result($notchDetails);
  • Ich würde beginnen mit php.net/manual/en/mysqli-result.free.php
  • Ist das nicht die Funktionen json_encode einer Weise zu serialisieren? Was ist das extra „serialisieren“ Schritt? (Glaube nicht, es ist das Nadelöhr, einfach Fragen)
  • Da mehrere json-strings und nicht-json-strings benötigt, kombiniert werden. Aber eigentlich bin ich nicht sicher, ob es wirklich ein problem, wenn ich nicht zu serialisieren. Könnte es versuchen. Vielen Dank für die Anregung
  • Zu erlauben, ein Skript für mehr hinzufügen ini_set('max_execution_time', 900); oben auf dein script. Oder Sie tun können ini_set('max_execution_time', 0); so kann es laufen, für immer
  • ich weiß, ich könnte das tun, und wahrscheinlich müssen. Aber das ist nicht die Lösung
  • Im gehend zu versuchen und sehen Sie den Unterschied
  • Ich glaube nicht, dass die verbrachte Zeit in den Datenbank-Zugriff zählt zu den max_execution_time
  • darum geht es nicht. es geht um mehr und mehr Arbeitsspeicher verwendet wird, verlangsamt das Skript, das ist, was er gefragt.
  • Wenn jeder dieser Dateien ist eine ungefähr gleiche Größe, ich würde vermuten das problem liegt, wie du bist, abrufen von Daten in den ersten Platz, anstatt, wie es ist auf die Festplatte geschrieben. Eine schlecht optimierte, nicht-indizierten Abfrage (die eine volle Tabelle Lesen) wird länger dauern, zu laufen auf Aufzeichnungen 190,000 – 200,000, als würde es auf die Datensätze 0 – 10,000 trotz der Tatsache, dass in jedem Fall, mehr als 10.000 Datensätze zurückgegeben werden.
  • Vielleicht, wenn Sie waren nicht so cryptic über Ihre echte code, konnten die Menschen machen vernünftige Vorschlag anstatt alle diese Vermutungen
  • Die mysqli_free_result did ‚ NT nichts ändern. Aber ich habe die Tabelle indiziert und es sind gerade mehr als 7000 Datensätze (ja, es groß)
  • Alle Datensätze sind genau die gleichen für Testzwecke.
  • bei jedem SELECT werden die Daten begrenzt, die mit LIMIT. Die Abfrage ist SELECT * FROM table WHERE projectid = ".$projectid." LIMIT ".$offset.", ".$limit.". Jede Schleife der offset und limit berechnet. projectid ist ein index
  • Nur weil eine Tabelle indiziert werden, es muss nicht unbedingt bedeuten, dass MySQL kann verwenden Sie index; es kommt auf die Abfrage an. MySQL kann in der Regel verwenden Sie nur jeweils einen index, zum Beispiel, wenn Sie haben eine Bedingung für ein WHERE und ein ORDER BY auf verschiedenen Indizes, die es werden wollen, eine vollständige Tabelle zu Lesen. Ich würde vorschlagen, bei der Ausführung Ihrer Abfrage direkt auf die Datenbank vorangestellt mit EXPLAIN : dev.mysql.com/doc/refman/5.7/en/explain.html

InformationsquelleAutor Ramon Bakker | 2016-02-24



One Reply
  1. 1

    Ich persönlich würde kodiert haben, diese als eine einzelne SELECT-mit no LIMIT und dann basierend auf einer $rec_per_file = ?; schreiben Sie die Ausgänge aus, die innerhalb der einzelnen while get results Schleife

    Entschuldigung für den kryptischen code, Sie nicht geben uns viel von eine Ahnung

    <?php
    //ini_set('max_execution_time', 600);    //only use if you have to
    
    $filename = 'something';
    $filename_suffix = 1;
    
    $rec_per_file = 100;
    
    $sql = "SELECT ....";
    
    Run query
    
    $rec_count = 0;
    
    while ( $row = fetch a row ) {
    
        $data[] = serialize > openssl_encrypyt
    
        $rec_count++;
    
        if ( $rec_count >= $rec_per_file ) {
    
            $json_string = json_encode($data);
    
            file_put_contents($filename.$filename_suffix, 
                              $json_string, 
                              LOCK_EX);
    
            $filename_suffix++; //inc the suffix
            $rec_count = 0;     //reset counter
            $data = array();    //clear data
    
            //add 30 seconds to the remaining max_execution_time
            //or at least a number >= to the time you expect this
            //while loop to get back to this if statement
            set_time_limit(30);
        }
    }
    //catch the last few rows
    $json_string = json_encode($data);
    file_put_contents($filename.$filename_suffix, $data, LOCK_EX);

    Bin ich auch nicht sicher, warum würden Sie wollen, um serialize() und json_encode()

    Hatte ich einen Gedanken, basierend auf Ihren Kommentar über die Ausführungszeit. Wenn Sie eine set_time_limit(seconds) innerhalb der if innerhalb der while Schleife, es könnte sauberer sein, und Sie würde nicht ini_set('max_execution_time', 600); eine sehr große Zahl, die, wenn Sie einen echten Fehler hier verursachen kann PHP weiter verarbeiten, für eine lange Zeit, bevor er das script aus.

    Aus der Anleitung:

    Legen Sie die Anzahl der Sekunden, die ein Skript laufen darf. Wenn dies erreicht ist, wird das Skript gibt einen schwerwiegenden Fehler. Der Standardwert ist 30 Sekunden, oder, falls vorhanden, die max_execution_time Wert definiert in der php.ini.

    Beim Aufruf set_time_limit() wird der timeout-Zähler von null. In anderen Worten, wenn der timeout ist standardmäßig auf 30 Sekunden und 25 Sekunden in die Skript-Ausführung ein Aufruf wie z.B. set_time_limit(20) erfolgt, wird das Skript ausgeführt wird, für eine Gesamtmenge von 45 Sekunden, bevor ein Timeout Eintritt.

    • Ich verstehe. Werde es versuchen morgen.
    • Ich wäre daran interessiert zu wissen, wenn ausgeführt, wie diese es laufen wird, innerhalb der 240 Sekunden des Standard – max_execution_time
    • Im definitily werde Euch wissen lassen, asap
    • Naja, die performance… :). Wie die Abfrage doen ‚ st, zählen die max-execution-time, und die Schrift ist 2,25 x schneller! Das bedeutet, dass mit einer Ausführungszeit von 240 Sekunden, ich kann schreiben, 1,6 GB, 45 Dateien x 37MB). Und es tut nicht langsamer zu werden überstunden, so dass dieser auf jeden Fall funktioniert!
    • Siehe aktualisierte Frage für den funktionierenden code

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.