Brauche hilfe bei performance und /oder besseren Code

basti1012

Erfahrenes Mitglied
Kurze erklärung zum Problem.
Habe einen Ordner mit 99999 Datein Ca.
Da stehen alle Strassennamen mit Geo Daten und co drinne.
Die Datein gehen von 01000.php bis 99999.php . Die Zahlen sind die Postleitzahlen.

In diesen Datein sieht es so aus.
Code:
[{"id":74510,"name":"Adolph-Kolping-Weg","gemeinde":"Gilching","plz":"82205","centr_lon":11.288130,"centr_lat":48.118161},
{"id":76162,"name":"Ahornstraße","gemeinde":"Gilching","plz":"82205","centr_lon":11.323844,"centr_lat":48.110645},
{"id":86007,"name":"Allinger Straße","gemeinde":"Gilching","plz":"82205","centr_lon":11.291399,"centr_lat":48.123642},
{"id":86491,"name":"Almersweg","gemeinde":"Gilching","plz":"82205","centr_lon":11.287451,"centr_lat":48.115983},
usw...

Am Anfang habe ich alle Datein durch eine Schleife gejagt und da ist klar das Php Timeout rauswirft.
Also hole ich jetzt immer nur eine Datei aus den Ordner und lese die dann so in der Db ein
PHP:
$inhalt=file_get_contents($link);
$gep=json_decode($inhalt,true);
//print_r($gep);
foreach ($gep as $geparst){
  $r++;
  $gesammt=$r;
  if($r<2000){// versucht zu begrenzen bei großen Datein
    $fileid=$geparst['id'];
    $name=$geparst['name'];
    $gemeinde=$geparst['gemeinde'];
    $plz=$geparst['plz'];
    $centr_lon=$geparst['centr_lon'];
    $centr_lat=$geparst['centr_lat'];
    $query="SELECT * FROM `stadt_strassen_datenbank1` WHERE `fileid`='$fileid' AND `name`='$name' AND `centr_lon`='$centr_lon'";
    $re=mysqli_query($mysqli,$query);
    if($re){
       $cnt = mysqli_num_rows($re);
       if($cnt>=1){
            //echo $fileid.' Schon  '.$cnt.' mal da<br>';
            $alt++;
       }else{
            $query1="INSERT INTO `stadt_strassen_datenbank1`(`fileid`, `name`, `gemeinde`, `plz`, `centr_lon`, `centr_lat`)
            VALUES ('$fileid','$name','$gemeinde','$plz','$centr_lon','$centr_lat')";

            $re1=mysqli_query($mysqli,$query1);
            if($re1){
                 //echo $fileid.' wurder erstellt<br>';
                 $neu++;
            }else{
                 $nicht='{"fileid":'.$fileid.', "name":'.$name.', "gemeinde":'.$gemeinde.', "plz":'.$plz.', "centr_lon":'.$centr_lon.', "centr_lat":'.$centr_lat.'"}';
                 file_put_contents('NOT_GESPEICHERT.php', $nicht, FILE_APPEND | LOCK_EX);

                 echo "Error INSERT: " . mysqli_error($mysqli) . "<br>";
                 $error++;
            }
       }
    }else{
         echo "Error SELECT: " . mysqli_error($mysqli) . "<br>";
    }
  }
}
if($error==0){
     unlink($link);
     $gel=$file.' Gelöscht';
}else{
     $gel=$file.' Nicht gelöscht';
}
Bitte keine aussagen zu sql und co weil der nur für mich einmalig zum einlesen ist.

Der Code Funktioniert soweit ganz gut.
Sind da aber mehr Einträge als ca 100 drinne kommt immer Timeout.
Datenbanken sollten doch mehr alls 100 Einträge lesen und schreiben können bis zum Timeout oder ?
Gibt da eine schnellere möglichkeit , oder was performance Technischer besser ist ?
 
Ist denn diese ID gobal eindeutig, d. h. über alle Dateien oder nur pro Datei, d. h. sie kann in verschiedenen Dateien mehrfach auftreten?
 
Bei allen Performanceproblemen: nutz einen Profiler oder zumindest time manuell, was wie lange braucht. Ohne das weißt du ja nicht einmal, woran es liegt, und verschwendest ggf. nur Zeit mit Optimieren unnötiger Stellen.

Flaschenhälse, die mir spontan einfallen:
  • file_get_contents + json_decode (unnötiger Speicherverbrauch; warum nicht streamen?)
  • Keine Prepared Statements => dasselbe SQL-Statement als String wird immer wieder und wieder geparst
  • Constraints (etwa UNIQUE) und Indizes in der Datenbank, die bei jedem INSERT überprüft werden
  • Das Einfügen von nur einer einzigen Zeile pro Iteration -- SQL Datenbanken sind nicht dafür gedacht, dass du mittels INSERT einen Bulk Insert machst, indem du nur eine Zeile jeweils einfügst. Dafür ist der Overhead PHP -> SQL Driver -> SQL Datenbank und zurück wahrscheinlich viel zu groß.

Gibt da eine schnellere möglichkeit , oder was performance Technischer besser ist ?
Zuerst profilen, dann nach "SQL Bulk Insert" googeln.
 
Wenn das nur einmalig ist und nicht auf gute Programmierung ankommt, dann lese die Daten blockweise ein. Also z.B. die ersten 50, dann eine Weiterleitung auf das gleiche Script mit Parameter, damit du weißt, wo das Script weiter machen soll.

Normalerweise würde ich sagen: schmeiß das Script weg, das ist Murks.
 
Das Script soll nur einmal zum Einsatz kommen bis alles in der Datenbank ist.
Ich werde erstmal das versuchen was ihr geschrieben habt und dann mal weiter sehen wie es läuft.

Das mit den blockweise habe ich auch versucht.
Das klappt auch ,aber dauert wie es jetzt ist ewig.
In eine Datei ( zb plz von Berlin ) können mal 3000 Strassennamen drinn sein.
Da kann man sich ja vorstellen wie lange das bei allen Plz Bereichen dauern kann.

Ich versuche erstmal eure Vorschläge , vor allem mit den streamen muß ich mal Googeln weil das sagt mir gerade nicht viel .
Danke schon mal.
 
Ist denn diese ID gobal eindeutig, d. h. über alle Dateien oder nur pro Datei, d. h. sie kann in verschiedenen Dateien mehrfach auftreten?
Die ids die bei den Strassennamen stehen sind meines wissens eindeutig und kommen nicht doppelt vor.
Diese id ist in meiner db "fileid".
Habe schon gedacht das ich die id auch als id in der Datenbank nutzen soll, dann brauch man ja eigentlich die SELECT Abfrage nicht mehr ?
Oder sehe ich das gerade falsch ?
 
Genau daran dachte ich bei meiner Frage. Ich denke, ein select mit where nach mehreren Feldern dürfte performance-intensiv sein. Ich habe mich gefragt, ob man das auch mit einem Constraint erreichen kann, dass sicher gestellt wird, dass ein Eintrag nur einmal vorkommen kann. Da wissen andere wahrscheinlich mehr.
 
Zurück