Thomas: 504 Gateway Time-out - Bei einem Update Script

Hallo,

wenn ich das nachfolgende Script auf meinem Webspace ausführe, erhalte ich nach ca. 5 Minuten folgende Meldung "504 Gateway Time-out" das bedeutet doch, dass der Server zu lange für das Ausführen des Script benötigt, richtig?

Meine Tabelle produkte hat 24023 Einträge und die Tabelle preise hat 15025 Einträge also eigentlich nicht viel? Kann man das Script vielleicht etwas optimieren oder sollte ein sleep Befehl eingebaut werden, wenn ja an welcher Stelle?

$update_preise = update_preise($mysqli);

if($update_preise > 0) {

    foreach($update_preise as $array){ 
          
        $stmt1 = $mysqli->prepare("SELECT Nr, Netto FROM preise WHERE Nr=?");
        $stmt1->bind_param("s", $array['artnr']);
        $stmt1->execute();
        $stmt1->bind_result($Nr, $Netto);
        $stmt1->store_result();
        $stmt1->fetch();
        
	if($stmt1->num_rows() >  0) {
 
            $Preis = str_replace(",", ".", $Netto);
            $Preis = number_format($Preis, 2, ',', ' ');
 
        } else {
            $Preis = $array['preis'];  
        }
		                
        if ($stmt = $mysqli->prepare("Update produkte SET preis=? WHERE artnr = ?")) {    

              $preis   = $Preis;
              $artnr   = $array['artnr'];  

              $stmt->bind_param("ss", $preis, $artnr);
              $stmt->execute();
         }
    } // /foreach
} else { echo "Keine Daten vorhanden"; }
  1. Mahlzeit,

    wenn ich das nachfolgende Script auf meinem Webspace ausführe, erhalte ich nach ca. 5 Minuten folgende Meldung "504 Gateway Time-out" das bedeutet doch, dass der Server zu lange für das Ausführen des Script benötigt, richtig?

    das wäre eine mögliche Erklärung. Eine andere wäre, dass das Script einen fatalen Fehler verursacht hat und PHP keine brauchbare HTTP-Ausgabe mehr erzeugen kann - bei einem direkten Request ohne Umweg über einen Proxy wäre das typischerweise ein "500 Internal Server Error".

    $update_preise = update_preise($mysqli);
    
    if($update_preise > 0) {
    
        foreach($update_preise as $array){ 
    

    STOP! Das sieht schon mal ziemlich falsch aus.

    Erstens ist es keine gute Idee, für eine Funktion und eine Variable den gleichen Bezeichner zu wählen. Das führt früher oder später zu Verwirrung.

    Zweitens: Was liefert denn deine Funktion update_preise() als Ergebnis? in der if-Abfrage vergleichst du dieses Ergebnis zunächst mit 0, erwartest also offensichtlich einen Zahlenwert. Und dann lässt du foreach darauf los, das ergibt aber nur einen Sinn, wenn es ein Array ist.

    Also was denn nun?

            $stmt1 = $mysqli->prepare("SELECT Nr, Netto FROM preise WHERE Nr=?");
            $stmt1->bind_param("s", $array['artnr']);
            $stmt1->execute();
            $stmt1->bind_result($Nr, $Netto);
            $stmt1->store_result();
            $stmt1->fetch();
    

    Das sind viele, viele aufeinanderfolgende Datenbankabfragen in einer Schleife. Schon möglich, dass das eine Weile dauert.

                $Preis = str_replace(",", ".", $Netto);
                $Preis = number_format($Preis, 2, ',', ' ');
    

    Auch Unsinn: Erst wandelst du den Zahlenwert $Netto in einen String und ersetzt Punkte durch Kommas, und dann übergibst du den String zur Aufbereitung an number_format()? Dabei wird er natürlich wieder in eine Zahl konvertiert, und das Komma und alles, was danach kommt, wird ignoriert.

            if ($stmt = $mysqli->prepare("Update produkte SET preis=? WHERE artnr = ?")) {    
    
                  $preis   = $Preis;
                  $artnr   = $array['artnr'];  
                  $stmt->bind_param("ss", $preis, $artnr);
    

    Autsch. Jetzt auch noch Bezeichner, die sich nur durch Groß/Kleinschreibung unterscheiden. Das ist ganz bestimmt keine gute Idee - abgesehen davon, dass das reine Umkopieren hier völlig unnötig ist, denn du könntest die Originaldaten auch direkt an bind_param() übergeben.
    Und ... Moment mal: Preis als String? Das ist'n Irrtum, oder?

    So long,
     Martin

    --
    Logik ist die Theorie, Chaos die Praxis.
    1. Hallo,

      der Fehler tritt an dieser Stelle auf

      					
      if ($stmt = $mysqli->prepare("Update produkte SET preis=? WHERE artnr = ?")) {    
      	
        $preis   = $Preis;
        $artnr   = $array['artnr'];  
      	
        $stmt->bind_param("ss", $preis, $artnr);
        $stmt->execute();
      }
      

      Rufe ich das Script ohne den oben genannten Teil auf, wird dieses in ca. 30 - 40 Sekunden abgearbeitet

      $update_preise_ausgabe = update_preise($mysqli);
      
      if($update_preise_ausgabe > 0) {
      
      	foreach($update_preise_ausgabe as $array){ 
      			  
      		$stmt1 = $mysqli->prepare("SELECT Nr, Netto FROM preise WHERE Nr=?");
      		$stmt1->bind_param("s", $array['artnr']);
      		$stmt1->execute();
      		$stmt1->bind_result($Nr, $Netto);
      		$stmt1->store_result();
      		$stmt1->fetch();
      				
      		if($stmt1->num_rows() >  0) {
      			 
      		$Preis = str_replace(",", ".", $Netto);
      		$Preis = number_format($Preis, 2, ',', ' ');
      			 
      		} else {
      		$Preis = $array['preis'];  
      		}
      		
      		echo $array['artnr'] ." ". $Preis;
      		echo "<br>";
      		
      } // /foreach
      } else { echo "Keine Daten vorhanden"; }
      

      Zu deiner Frage:

      Zweitens: Was liefert denn deine Funktion update_preise() als Ergebnis?

      update_preise() liefert mir alle Einträge aus der Tabelle produkte

      1. Hallo,

        hab mein Script etwas aufgeräumt und überarbeitet. Fehler tritt leider noch immer auf

        <?php 
        // Alle Artikel aus der Datenbank auslesen
        $update_preise_ausgabe  = update_preise($mysqli);
        
        // Prüfen ob Artikel vorhanden sind, wenn nicht in den else Bereich gehen mit passender Ausgabe
        if($update_preise_ausgabe  > 0) {
        	
        	// Schleife durchlaufen von update_preise_ausgabe 
            foreach($update_preise_ausgabe  as $array){ 
        	         
        		// Neue Preise aus einer zweiten Tabelle auslesen	  
                $stmt1 = $mysqli->prepare("SELECT Nr, Netto FROM preise WHERE Nr=?");
                $stmt1->bind_param("s", $array['artnr']);
                $stmt1->execute();
                $stmt1->bind_result($Nr, $Netto);
                $stmt1->store_result();
                $stmt1->fetch();
                
        		if($stmt1->num_rows() >  0) {
                    
        			$Preis = $Netto;
               
        	    } else {
                    $Preis = $array['p_preis'];  
                }
        		
        		// Demo Ausgabe um zu schauen ob bis zu diesem Zeitpunkt ein Fehler auftaucht
        		echo $array['artnr'] ." ". $Preis;
        		echo "<br>";
        		 
        		// Hier werden die alten Preise mit den neuen Preise überschrieben                
                if ($stmt = $mysqli->prepare("Update produkte SET preis=? WHERE artnr = ?")) {    
                                 
        			  $stmt->bind_param("ss", $Preis, $array['artnr']);
                      $stmt->execute();
                 }
        	
            } // Ende der foreach
        
        } else { echo "Keine Daten vorhanden"; }
        ?>
        
      2. Zweitens: Was liefert denn deine Funktion update_preise() als Ergebnis?

        update_preise() liefert mir alle Einträge aus der Tabelle produkte

        Der Name "update_preise" wäre der richtige Name für das komplette Codefragment das Du uns gepostet hast. Eine Funktion, die eine Tabelle aller Produkte liefert, sollte auch so heißen: "get_produkte" oder "getProdukte".

        1. Hi,

          Der Name "update_preise" wäre der richtige Name für das komplette Codefragment das Du uns gepostet hast. Eine Funktion, die eine Tabelle aller Produkte liefert, sollte auch so heißen: "get_produkte" oder "getProdukte".

          nein, bitte nicht. Meinetwegen ListeProdukte() oder GetProducts(), aber dieser Deutsch-Englisch-Mix ist furchtbar.

          Ciao,
           Martin

          --
          Logik ist die Theorie, Chaos die Praxis.
    2. Tach,

      Eine andere wäre, dass das Script einen fatalen Fehler verursacht hat und PHP keine brauchbare HTTP-Ausgabe mehr erzeugen kann - bei einem direkten Request ohne Umweg über einen Proxy wäre das typischerweise ein "500 Internal Server Error".

      nein, ein 500 sendet Daten an den Proxy und dieser leitet sie weiter, die Verbindung wird beendet und es kann kein 504 mehr auftreten; 504 wird nur erzeugt, wenn der Proxy entscheidet, dass vom eigentlichen Server keine Daten mehr kommen, entweder weil ein interner Timeout eingetreten ist oder die Verbindung zwischen Proxy und Server getrennt wurde.

      mfg
      Woodfighter

  2. Hallo,

    wenn ich das nachfolgende Script auf meinem Webspace ausführe, erhalte ich nach ca. 5 Minuten folgende Meldung "504 Gateway Time-out" das bedeutet doch, dass der Server zu lange für das Ausführen des Script benötigt, richtig?

    Nein. Nicht der Server sondern der Prozess am anderen Ende des Gateway braucht zu lange (das G in CGI steht für Gateway).

  3. Hallo Thomas,

    der Frage zum Datentyp möchte ich mich anschließen. Ist der Preis ein String? Wenn ja, warum? Es gibt auch den Datentyp DECIMAL, da kannst Du festlegen, dass Du 2 Nachkommastellen haben willst.

    Zum SQL: Da du pro Produkt einen SELECT auf die Preise-Tabelle und einen UPDATE auf die Produkte Tabelle machst, ist es keine Kleinigkeit, was Du da treibst. 48047 separate SQL Zugriffe sind schon einiges, und wenn der SQL Server auch für andere Leute aktiv ist, kann das dauern. Du musst Dich ja mit jeder Query neu hinten in der Warteschlange anstellen :). Und - hast Du Indizes auf Preise.Nr und Produkte.ArtNr gelegt?

    Wenn Du unbedingt jeden Preis im Programm verarbeiten musst - was nicht zwingend der Fall ist - dann könntest Du die Anzahl der Queries schon mal halbieren indem Du die Produkte mit EINER Query in eine eigene Tabelle lädst und dann dort die Preise heraussuchst.

    Ob man mit mysqli so etwas wie einen Update-Cursor machen kann, weiß ich nicht; aber wenn ja, könntest Du die Produkte mit einem Update-Cursor durchlaufen und nicht für jeden Preis ein separates Update-Statement absetzen.

    Du kannst für den Fall, dass ein Produkt keinen Eintrag in der Preise-Tabelle hat, auch auf den Update ganz verzichten.

    Wenn mysqli->prepare so funktioniert wie ich das erwarte, dann musst Du auch nicht in jedem Schleifendurchlauf den prepare machen. Der dürfte Zeit kosten. Statt dessen kannst Du ihn vor die Schleife ziehen und in der Schleife nur den bind_param machen. Das ist meines Wissens der SINN von prepared Statements.

    Ja, und dann wäre noch diese Variante:

    UPDATE Produkte 
       SET Preis = COALESCE((SELECT Netto
                             FROM Preise
                             WHERE Preise.Nr = Produkte.ArtNr), Produkte.Preis)
    

    Das ist eine einzige Query. Der innere SELECT liefert NULL wenn es zu einem Produkt keinen Preis gibt, und COALESCE liefert den ersten seiner Parameter zurück, der nicht NULL ist. Heißt: Gibt's einen Preis bei Preise, wird er übernommen, andernfalls der alte Preis beibehalten. Das wolltest Du doch, oder?

    Gruß Rolf

    1. PS: Wenn Du mit String hantierst weil bind_param in der Typenliste kein NUMERIC oder DECIMAL kennt - dann binde dort an Double (Kennbuchstabe d). Und deine Artikelnummer ist bestimmt auch kein String, oder doch? Integers bindet man mit i.

      1. PPS: Damn, ich will mich länger als 20 Minuten editieren dürfen ;-)

        Korrektur: "...halbieren indem Du die Produkte mit EINER Query..." - es muss natürlich Preise heißen.

      2. Hi,

        PS: Wenn Du mit String hantierst weil bind_param in der Typenliste kein NUMERIC oder DECIMAL kennt - dann binde dort an Double (Kennbuchstabe d).

        das hatte ich ja zumindest schon angedeutet, auch wenn ich mich mit Prepared Statements bisher wenig auskenne.

        Und deine Artikelnummer ist bestimmt auch kein String, oder doch? Integers bindet man mit i.

        Artikelnummern sind gerne mal alphanumerisch oder haben Zeichen wie Punkte oder Bindestriche ...

        So long,
         Martin

        --
        Logik ist die Theorie, Chaos die Praxis.
    2. Hallo Rolf,

      vielen Dank für deine sehr ausführliche Erklärung. Ich erkläre dir kurz mein Aufbau beider Tabellen:

      In der Tabelle preise gibt es wie aus dem Code zu erkennen zwei Spalten, in der Spalte Nr steht eine Artikelnummer, in der Spalte Netto steht der Preis in folgender Schreibweise 1,99 (was auch passt, dieses habe ich bereits in meiner CSV Datei angepasst).

      In der Tabelle produkte stehe meine Produkte. Dort gibt es eine Spalte preis in dieser steht wie zu ahnen mein „alter“ Preis. In der Spalte artnr steht die dazugehörige Artikelnummer.

      Folgendes soll das Script nun erledigen:

      Gehe in die Tabelle „produkte“ schnapp dir dort eine Artikelnummer, gehe mit dieser in die Tabelle „preise“ schau dort nach der zuvor aufgenommen Artikelnummer, schnapp dir den dazugehörigen Preis und führe in der Tabelle „produkte“ ein Update durch.

      Genau dieses will / wollte ich mit dem Script erreichen. Ich hoffe ich habe es deutlich genug rüber gebracht.

      Die Artikelnummer kann Zahlen und Buchstaben enthalten, sollte dieses noch wichtig sein.

      1. Folgendes soll das Script nun erledigen:

        Gehe in die Tabelle „produkte“ schnapp dir dort eine Artikelnummer, gehe mit dieser in die Tabelle „preise“ schau dort nach der zuvor aufgenommen Artikelnummer, schnapp dir den dazugehörigen Preis und führe in der Tabelle „produkte“ ein Update durch.

        Das Problem ist die hohe Anzahl der Schleifendurchläufe, kombiniert mit mit der resultierenden hohen Anzahl an einzeln übermittelten SQL-Anweisungen. Womöglich gibt es weitere Probleme infolge fehlender Indexierung der Tabellen und/oder das eines "weit entfernten" Datenbankservers. Nur dann kann bei diesen Zeilenzahlen ein TimeOut erfolgen.

        Hier die Lösung:

        Sende genau einen Befehl an die Datenbank und überlasse lasse dieser die "Durchläufe". Dazu ist ein Join zu bauen, hier reicht ein implizierter:

        Tabelle test_preise vorher:

        Alternativ-Text

        Tabelle test_produkte vorher:

        Alternativ-Text

        sql:

        UPDATE test_produkte, test_preise
         SET test_produkte.preis = test_preise.preis
         WHERE test_produkte.artikelnummer = test_preise.artikelnummer
         AND  test_produkte.preis <> test_preise.preis
        

        Tabelle test_produkte danach:

        Alternativ-Text

        Das war wohl gefragt...

      2. Hallo Rolf,

        vielen Dank für deine sehr ausführliche Erklärung. Ich erkläre dir kurz mein Aufbau beider Tabellen: (...) Gehe in die Tabelle „produkte“ schnapp dir dort eine Artikelnummer, gehe mit dieser in die Tabelle „preise“ schau dort nach der zuvor aufgenommen Artikelnummer, schnapp dir den dazugehörigen Preis und führe in der Tabelle „produkte“ ein Update durch.

        Genau dieses will / wollte ich mit dem Script erreichen. Ich hoffe ich habe es deutlich genug rüber gebracht.

        Und genau das tut mein SQL-Statement. "Google weiß alles" meint zwar, auf den COALESCE darin verzichten zu können, aber es sieht so aus als hättest Du nicht zu jedem Produkt einen Preis, darum muss das 'rein. Wenn Du den Preis als String speicherst, dann solltest Du das in NUMERIC oder DECIMAL ändern. Kannst Du auch aus CSV importieren.

        Gruß Rolf

        1. Und genau das tut mein SQL-Statement. "Google weiß alles" meint zwar, auf den COALESCE darin verzichten zu können, aber es sieht so aus als hättest Du nicht zu jedem Produkt einen Preis

          Sieht so aus, als würden beide Lösungen funktionieren. Übrigens auch wenn in preise weniger Einträge stehen als in produkte oder wenn in produkte Einträge vorhanden sind, die in preise nicht stehen... (mit meiner Abfrage habe ich das gerade rein sicherheitshalber auch getestet.

          Im übrigen habe ich natürlich "ordentliche" Datentypen (INT, DEZIMAL) verwendet.

          1. Bei mir war es so, dass ohne den COALESCE der Preis auf 0 gesetzt wurde (oder "" oder NULL je nach Spaltentyp), wenn in der Produktetabelle eine Artikelnummer stand, die es in der Preistabelle nicht gab. Und das sollte ja laut Thomas' ursprünglichem Script nicht sein, sondern der alte Preis behalten werden. Mein Spaltentyp war DECIMAL - aber ich glaube nicht dass das bei VARCHAR(200) anders ist.

            Gruß Rolf

            1. Bei mir war es so, dass ohne den COALESCE der Preis auf 0 gesetzt wurde

              Kein Wunder. Du arbeitest mit einem Subselect, ich mit einem Join. Für Dein Vorgehen braucht es COALESCE, für meines nicht. Dieses weil ich nicht existierende Zeilen durch die WHERE-Clausel sauber ausschließe.

        2. Und genau das tut mein SQL-Statement. "Google weiß alles" meint zwar, auf den COALESCE darin verzichten zu können, aber es sieht so aus als hättest Du nicht zu jedem Produkt einen Preis, darum muss das 'rein. Wenn Du den Preis als String speicherst, dann solltest Du das in NUMERIC oder DECIMAL ändern. Kannst Du auch aus CSV importieren.

          Hallo,

          danke nochmals für dein Beispiel. Ich habe mir zwei Demo Tabellen angelegt, die wie folgt aussehen:

          CREATE TABLE IF NOT EXISTS `test1` (
          `id` int(11) NOT NULL,
            `artnr` varchar(200) NOT NULL,
            `preis` varchar(200) NOT NULL
          ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
          
          CREATE TABLE IF NOT EXISTS `test2` (
          `id` int(11) NOT NULL,
            `artNr` varchar(200) NOT NULL,
            `Netto` varchar(200) NOT NULL
          ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
          

          Danach habe ich dein Script ausführen lassen:

          UPDATE test1 
             SET preis = COALESCE((SELECT Netto
               FROM test2
               WHERE test2.artNr = test1.artnr), test1.preis)
          

          Dazu bin ich in phpMyAdmin gegangen dann auf SQL und habe diesen Code eingefügt. Hat auch alles soweit geklappt, gut waren auch nur 10 Datensätze.

          Was ich aber nicht ganz verstehe, warum hat der Server mit diesem Update weniger zu tun? Er muss doch ebenfalls alle Datensätze durchgehen, oder?

          1. Was ich aber nicht ganz verstehe, warum hat der Server mit diesem Update weniger zu tun? Er muss doch ebenfalls alle Datensätze durchgehen, oder?

            Stell Dir die Programme als Worker vor, also als menschliche Arbeiter, die einen Job erledigen sollen. Du hast davon 3: Webserver, PHP, Datenbankserver.

            Bei Deinem Skript führen PHP und der Datenbankserver eine endlose Diskussion und PHP wartet jedes (in Deinem Fall wohl rund 28000) Mal höflich auf die Bestätigung vom Datenbankserver, verarbeitet diese und sendet dann den nächsten Befehl ... um wieder zu warten, die Antwort zu verarbeiten, den nächsten Befehl zu senden ... irgendwann hat der ebenfalls (auf PHP, vom Datenbankserver weiß er nichts) wartende Webserver die Schnauze voll, haut PHP mit der Schaufel tot und schickt dem Chef die Meldung: "Eh! Der faule Hund PHP wird ewig nicht fertig. Hab ihn erwürgt und erledige jetzt den nächsten Job. Die Gewerkschaft sagt, ich darf das!" (Beim Apache wäre der Chef übrigens auch ein Apache, nämlich der "Vaterprozess" der die Worker steuert. Dessen "Chef" ist unter Unix/Linux dann der Herr "init", dessen Boss ist der Kernel...)

            Hinzu kommt: Der Datenbankserver bekommt eine Anweisung und führt diese aus. Enthält EIN Befehl EINE Einfüge-oder Änderungsoperation so muss er danach "aufräumen" (z.B. Indexe erneuern, den Ausgabekanal öffnen und melden was er getan hat und ob das klappte: Hier etwas wie "1 Zeile betroffen"). Er macht das also auch 28000 mal. Führt er auf Grund EINES anderen Befehles die 28000 Operationen aus, dann "räumt er einmal auf" und meldet EIN mal etwas wie: "28000 Zeilen betroffen"

            Es ist ziemlich offensichtlich, dass das schneller geht - oder?

        3. Hallo Rolf,

          leider bekomme ich auch bei deiner Version eine Fehlermeldung, dieses mal lautet sie wie folgt:

          SELECT MAX(version) FROM phpmyadmin.pma_tracking WHERE db_name = 'db_webseite' AND table_name = 'produkte' AND FIND_IN_SET('UPDATE',tracking) > 0

          MySQL meldet: #2006 - MySQL server has gone away

          1. Hallo Rolf,

            leider bekomme ich auch bei deiner Version eine Fehlermeldung, dieses mal lautet sie wie folgt:

            SELECT MAX(version) FROM phpmyadmin.pma_tracking WHERE db_name = 'db_webseite' AND table_name = 'produkte' AND FIND_IN_SET('UPDATE',tracking) > 0

            MySQL meldet: #2006 - MySQL server has gone away

            Schalte das Tracking des PHPMyAdmin für die Datenbank bzw. Tabelle ab. Je nach Version ist das unterschiedlich "buggy" und geht besonders bei großen Tabellen auch mal schief. Mit der ursprünglichen Abfrage vom Rolf hat das auch nichts tun - nur mit dem PHPMyAdmin.

            1. Danke. Wieder was gelernt :) Offenbar hatte ich mit meinen phpadmin Versionen bisher Glück.

              Gruß Rolf

            2. Hallo,

              Schalte das Tracking des PHPMyAdmin für die Datenbank bzw. Tabelle ab. Je nach Version ist das unterschiedlich "buggy" und geht besonders bei großen Tabellen auch mal schief. Mit der ursprünglichen Abfrage vom Rolf hat das auch nichts tun - nur mit dem PHPMyAdmin.

              da ich keinen eigenen Server habe sondern nur Webspace gehe ich davon aus, dass ich dieses nicht selber abschalten kann? Vielleicht bringt es mir etwas, wenn ich meinen eigenen phpMyAdmin installiere?

              1. da ich keinen eigenen Server habe sondern nur Webspace gehe ich davon aus, dass ich dieses nicht selber abschalten kann?

                Schau Dich mal in den Tabs des phpMyAdmin undin den Optionen zu Tabellen und Datenbanken um. Da steht auch was von Tracking...

                Vielleicht bringt es mir etwas, wenn ich meinen eigenen phpMyAdmin installiere?

                Fragt sich, ob Du das pflegen willst.

                Da ich meine Datenbanken online erreichen kann habe ich ihn auf einem "Server" laufen und die Daten der Server bzw. Datenbanken fest konfiguriert. Den Zugang zum phpMyAdmin selbst schütze ich ganz normal mit htaccess.

                Allerdings benutze ich ihn fast nie. Hier hab ich ihn nur genommen, weil die Bildschirmfotos der Tabellen so schön einfach zu machen sind.

                1. Hallo,

                  Schau Dich mal in den Tabs des phpMyAdmin undin den Optionen zu Tabellen und Datenbanken um. Da steht auch was von Tracking...

                  die Einstellungen sehe ich zwar, kann diese aber nicht überschreiben, wird vom Server-Anbieter wohl unterbunden.

                  Ich installiere mir einfach kurz den phpMyAdmin von Hand und wenn alles erledigt ist lösche ich diesen wieder. Hoffentlich kommen solche Preisänderungen nicht zu oft.

                  Vielleicht sollte ich meine Datenbankstruktur ändern und zwar speichere ich pro Artikel den Preis mit in der Haupttabelle, vielleicht greife ich einfach in die neu eingespielte Tabelle zu, dann habe ich immer die aktuellen Preise.

                  1. vielleicht greife ich einfach in die neu eingespielte Tabelle zu, dann habe ich immer die aktuellen Preise.

                    Die Tatsache, dass Preise dann in mehreren Tabellen auftauchen, scheint mir ein schwerer Designfehler zu sein. Du brauchst ein wenig Theorie: Bitte lese über "Datenbankdesign" und "Normalisierung" nach.

                    Das zu richten macht jetzt einmal Arbeit. Das jetzt nicht zu korrigieren immer wieder und es wird zu Problemen führen, deren Ursache nicht einfach zu durchschauen ist, also viel Zeit frisst und womöglich sogar darin endet, dass alles neu geschrieben werden muss.

                    1. Hallo,

                      jetzt habe ich meinen eigenen phpMyAdmin installiert. Läuft auch und ich kann auf meiner Tabelle zugreifen. Lass ich nun das Script laufen, erhalte ich einen Fehlercode 500 - Fehlertext: Internal erver Error.

                      In meinen Logofiles steht folgendes:

                      [Sat May 07 18:19:02 2016] [error] [client xx.xxx.xxx.xxx] Script timed out before returning headers: import.php, referer: http://phpmyadmin.example.com/db_sql.php?db=artikel&token=901010b74a79b0c06bdd5e6ee913498a

                      Die Maximale Ausführungszeit habe ich bereits auf 0 gesetzt.

                      Alternativ-Text

                      An was könnte es jetzt noch liegen? Ach ja lass ich eine Simulation durchlaufen

                      Alternativ-Text

                      erhalte ich die Meldung

                      Gefundene Zeilen: 1

                      das heißt das Script hat ein Artikel gefunden, der unterschiedliche Preise von der einen zur anderen Tabelle hat, dieses stimmt auch.

                      Jetzt aber die Frage, warum funktioniert die Simulation, die Live-Abfrage nicht? Ist doch wie verhext?

                      1. Die Maximale Ausführungszeit habe ich bereits auf 0 gesetzt.

                        Ich weiß nichts darüber, ob und in welchen Grenzen Deine Einstellungen (die Du offenbar auf einer Webseite Deines Anbieters) vornimmst wirksam werden.

                        Jetzt aber die Frage, warum funktioniert die Simulation, die Live-Abfrage nicht? Ist doch wie verhext?

                        Weil die Simulation weniger Arbeit macht: Diese ändert ja nichts. Also gibt es nichts auf Platten zu schreiben und dann aufzuräumen.

                        Hast Du denn mal meine Methode mit dem Join probiert?

                        Auf den phpMyadmin kommt es hier nicht an. Der ist in Bezug auf das ursprüngliche Problem völlig nebensächlich.

                        Ohnehin solltest Du hier mal einen Dump Deiner Tabellen (ohne Daten) vorstellen, damit wir sehen was Du da hast. Man kann beim Einrichten der Tabellen sehr viel falsch machen. Es können z.B. Indexe fehlen was womöglich das Update extrem verlangsamt.

                        1. Hallo,

                          Ohnehin solltest Du hier mal einen Dump Deiner Tabellen (ohne Daten) vorstellen, damit wir sehen was Du da hast. Man kann beim Einrichten der Tabellen sehr viel falsch machen. Es können z.B. Indexe fehlen was womöglich das Update extrem verlangsamt.

                          hier die gewünschten Daten

                          CREATE TABLE IF NOT EXISTS `preise` (
                            `Nr` varchar(100) NOT NULL,
                            `Netto` varchar(100) NOT NULL
                          ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                          
                          
                          CREATE TABLE IF NOT EXISTS `produkte` (
                            `id` int(11) NOT NULL,
                            `artnr` varchar(200) NOT NULL,
                            `preis` varchar(100) NOT NULL
                          ) ENGINE=InnoDB AUTO_INCREMENT=24190 DEFAULT CHARSET=utf8;
                          

                          Hast Du denn mal meine Methode mit dem Join probiert?

                          Nein bis jetzt noch nicht, da der Einwand kam, dass wenn keine Daten gefunden werden diese auf 0 gesetzt werden, was in meinem Fall mehr als schlecht wäre :/

                          1. CREATE TABLE IF NOT EXISTS `preise` (
                              `Nr` varchar(100) NOT NULL,
                              `Netto` varchar(100) NOT NULL
                            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                            
                            
                            CREATE TABLE IF NOT EXISTS `produkte` (
                              `id` int(11) NOT NULL,
                              `artnr` varchar(200) NOT NULL,
                              `preis` varchar(100) NOT NULL
                            ) ENGINE=InnoDB AUTO_INCREMENT=24190 DEFAULT CHARSET=utf8;
                            

                            Dachte ich es mir: Keine Indexe. Fehleralarm! Du hast wirklich ALLES (außer ein paar sleeps einzubauen) dafür getan, dass Dein Progrämmchen zu lange bracht.

                            Nein bis jetzt noch nicht, da der Einwand kam, dass wenn keine Daten gefunden werden diese auf 0 gesetzt werden, was in meinem Fall mehr als schlecht wäre :/

                            Der Einwand ist wohl obsolet, denn er galt nur für die Methode von Rolf.

                            Du weist noch nicht wie man sich mit phpMyAdmin ein Backup bzw. Kopien erzeugt und mit diesen testet?

                            1. Hallo,

                              Dachte ich es mir: Keine Indexe. Fehleralarm! Du hast wirklich ALLES (außer ein paar sleeps einzubauen) dafür getan, dass Dein Progrämmchen zu lange bracht.

                              in der Tabelle preise setze ich einen Index auf Nr und in der Tabelle produkte auf artnr, richtig?

                              1. Hallo,

                                in der Tabelle preise setze ich einen Index auf Nr und in der Tabelle produkte auf artnr, richtig?

                                ich habe jetzt wie oben beschrieben jeweils einen Index vergeben, hab dann die Abfrage nochmals ausgeführt und ich kann es nicht glauben.

                                (Die Abfrage dauerte 0.1279 Sekunden.

                                Kannst du mir vielleicht kurz erklären was durch den index jetzt passiert ist?

                                1. Tach!

                                  Kannst du mir vielleicht kurz erklären was durch den index jetzt passiert ist?

                                  Ein Index ist wie ein Stichwortverzeichnis in einem Buch. Man schaut einfach dort nach (die alphabetische Sortierung hilft dabei sehr) und kann dann gezielt die Seite aufschlagen. Anderenfalls muss man das gesamte Buch durchblättern, um die gewünschte Information zu finden.

                                  dedlfix.

                                  1. Hallo,

                                    Ein Index ist wie ein Stichwortverzeichnis in einem Buch. Man schaut einfach dort nach (die alphabetische Sortierung hilft dabei sehr) und kann dann gezielt die Seite aufschlagen. Anderenfalls muss man das gesamte Buch durchblättern, um die gewünschte Information zu finden.

                                    danke für deine Erklärung. Eine Frage habe ich noch dazu, wenn neue Einträge hinzukommen, wird der Index automatisch erweitert / erneuert?

                                    1. Tach!

                                      Eine Frage habe ich noch dazu, wenn neue Einträge hinzukommen, wird der Index automatisch erweitert / erneuert?

                                      Ja, er wird selbständig vom DBMS gepflegt. Du musst nur festlegen, was du indexiert haben möchtest. Üblicherweise die Felder, anhand derer du Datensätze finden möchtest.

                                      dedlfix.

                                      1. Hallo,

                                        Ja, er wird selbständig vom DBMS gepflegt. Du musst nur festlegen, was du indexiert haben möchtest. Üblicherweise die Felder, anhand derer du Datensätze finden möchtest.

                                        danke für die Erklärung.

                                    2. Hi,

                                      Ein Index ist wie ein Stichwortverzeichnis in einem Buch. Man schaut einfach dort nach (die alphabetische Sortierung hilft dabei sehr) und kann dann gezielt die Seite aufschlagen. Anderenfalls muss man das gesamte Buch durchblättern, um die gewünschte Information zu finden.

                                      danke für deine Erklärung. Eine Frage habe ich noch dazu, wenn neue Einträge hinzukommen, wird der Index automatisch erweitert / erneuert?

                                      ja.

                                      Daher verlangsamen Indizes schreibende Operationen (insert, update) minimal, weil auch die Indizes gepflegt werden müssen.

                                      Als Ausgleich beschleunigen sie, wenn richtig eingesetzt, lesende Operationen (select, aber auch das where bei update/delete) ggf. erheblich.

                                      cu,
                                      Andreas a/k/a MudGuard