For-Schleife wird erschreckend langsam



  • Also laut Taskmanager habe ich eine konstante Auslastung von 18 MB. Ich habe die beiden Klassen schonmal vor einiger Zeit hier gepostet. Die anderen Schleifen unter 4.000 laufen auch sehr schnell durch. Ich greife bei den Results auf ein Array zurück.

    //Gibt den Wert einer Zelle zurueck. Angegeben wird die Zeilennummer
    //und die FeldNummer oder der Feldname.
    const char * CMySQLQuery::GetCharValue(const unsigned int nRowIndex, const unsigned int nFieldIndex)
    {
    	//Field-Index ausserhalb des gueltigen Bereichs
    	if (nFieldIndex < 0 || nFieldIndex > m_lFieldsCount -1)
    		return NULL;
    
    	//Row-Index ausserhalb des gueltigen Bereichs
    	if (nRowIndex < 0 || nRowIndex > m_lResultCount-1)
    		return NULL;
    
    	mysql_data_seek(m_MySQLResult, nRowIndex);
    	m_MySQLRow = mysql_fetch_row (m_MySQLResult);
    
    	return m_MySQLRow[nFieldIndex];
    }
    

    Könnte es sein, dass return m_MySQLRow[1]; schneller ist als return m_MySQLRow[5000]; ?



  • Das sollte keinen Unterschied machen, ist ja nur einfache Zeigerarithmetik.



  • könnte es sein, dass du schwierigkeiten von der mysql seite her bekommst? versuch doch zum spass mal nicht alles auf einmal, sondern immer in 1000er blöcken. vielleicht geht das zügiger?



  • Ich weiss nicht, wie gut MySQL die Abfragen cached, aber du machst bei jedem Schleifendurchgang für jedes Feld ein neues mysql_data_seek und mysql_fetch_row. Ich denke, dass dies bei der GetCharValue Methode auch der Fall ist, die ein char const * als zweiten Parameter erhält.

    MySQL wird bestimmt auch eine Art iterator anbieten, mit dem du durch den Datenbestand linear durchgehst. Das sollte am schnellsten sein.



  • Welches Indexfeld du zurück gibst, ist egal. Hat keinen Einfluss auf Performance.

    Aber ein anderer Gedanke: wer sagt denn, das dein Programm daran schuld ist, und nicht die Datenbank selbst? 💡 Vielleicht kann die das einfach nicht, mal so ebend so viele Statements hintereinander verarbeiten, ohne langsamer zu werden? Schliesslich ist die MySQL nur für ihre Query-Performance und nicht Schreib-Performance bekannt.

    Hast du vielleicht auch Transaktionen benutzt, die es langsamer machen könnten?

    Würde es ansonst mit einer anderen DB ausprobieren, um einen Gegentest zu machen. Z.B. mit einer "richtigen" DB wie Oracle. 😉



  • @ponto
    soweit ich weiss wird mit

    mysql_data_seek
    

    der Cursor innerhalb des Results bewegt und mit

    mysql_fetch_row
    

    wird die Zeile, an die der Cursor steht kopiert. Mir sind leider keinen anderen Methoden bekannt, um an Ergebnisse heranzukommen.

    @Artchi
    MySQL ist leider vorgegeben 🙂 Der Datenbankserver läuft zu Testzwecken hier lokal und trotzdem habe ich diese Probleme. Ich bin schon am überlegen, welche Ausreden mir einfallen, um dieses als "normal" zu verkaufen 😕

    @Korbinian
    Ja, dass scheint mir bisher auch die beste Methode zu sein, aber ich weiss nur noch nicht wie. Ich frage ja mit "SELECT * FROM..." ab und bekomme als Ergebnis alle Daten. Wenn ich jetzt selektiere mit von bis, habe ich bestimmt wieder das gleiche in Grün.



  • SciFi schrieb:

    @Artchi
    MySQL ist leider vorgegeben 🙂 Der Datenbankserver läuft zu Testzwecken hier lokal und trotzdem habe ich diese Probleme. Ich bin schon am überlegen, welche Ausreden mir einfallen, um dieses als "normal" zu verkaufen 😕

    Naja, was hat das denn mit lokal zu tun? Wenn der Server langsam wird, dann wird er langsam, egal ob lokal oder remote. Der Datentransfer von A nach B hat damit ja nichts zu tun. Sondern ganz einfach, das die DB nach jedem Insert vielleicht seine Daten organisieren muß... Indexieren und sonstigen pipapo. Bei 13.000 Inserts kann die DB schon gut ins Schwitzen kommen.

    Die Datenbank ist ein Fremdprodukt, für uns alle eine Blackbox. Es wäre nichts ungewöhnliches, wenn die DB ganz einfach der Flaschenhals ist. Warum auch nicht? Nicht umsonst gibts Benchmark-Tests die Massendaten-Performance auf DBs testen. Nicht umsonst wird in Konzernen für Massendaten kein PC sondern ein IBM-Mainframe eingesetzt, der trotzdem Sekunden für ein Select braucht.

    Da kann eine kostenlose MySQL schon mal schlapp machen.

    Was passiert denn, wenn du das Insert-Statement raus nimmst? (also die ganze Codezeile) Wenn es dann nicht langsamer wird, ist die DB erstmal schuld.

    Du solltest vielleicht mal andere MySQL-User fragen. Oder vielleicht gibts schon sowas in einer FAQ im Web?



  • Achja, warum machst du eigentlich 13.000 Inserts? Ganz dumm aber e4rnsthaft gefragt. 😃

    Dem Kunden oder deinem Chef würde ich einfach mal einen gleichen Test auf einer Oracle oder so präsentieren, falls diese schneller ist. Kann ich nicht versichern, aber dann haste Beweise das es nicht an deinem Code liegt.



  • Kopierst Du von mySQL nach mySQL?
    Dann gib es folgende Alternativen:
    insert into ... select (http://dev.mysql.com/doc/mysql/en/insert-select.html)
    Load Data infile (http://dev.mysql.com/doc/mysql/en/load-data.html)

    Allgemein: http://dev.mysql.com/doc/mysql/en/insert-speed.html

    Wenn Du von mySQL in einer andere DB (z.B. Oracle) kopierst, solltest Du Dir die import Features dieses DBMS anschauen. Und dann ist meistens am besten, über eine Datei zu importieren.

    Eine weitere wichtige Rolle bei der Einfügegeschwindigkeit spielen Transaktionen.

    Solche Fragen gehören eher ins Datenbank Forum...



  • schonmal ausprobiert einfach die forschleife umzudrehen? Also

    for (nIndex = Import->GetResultCount()-1; nIndex >= 0; nIndex--)
    

    😉



  • niemand schrieb:

    Kopierst Du von mySQL nach mySQL?
    Load Data infile

    Ui ui, hat MySQL keine Storedprocedures??? 😮

    SPs haben heute wegen Preparedstatements fast keine Daseinsberechtigung, aber für solche Dinge sind sie natürlich weiter unerlässlich.



  • Also ich kopiere Daten von einer Software zu einer anderen. Die Datenbanken sind in vielen Punkten ähnlich, aber nicht gleich. Das ganze ist ein grösseres Software-Update.

    Ich habe jetzt mal das INSERT Statement entfernt und siehe da, es rattert nur so durch. Darauf muss man erst mal kommen.

    Ich werde mich mal durch den Link von 'niemand' durcharbeiten, aber ich habe jetzt schonmal einen Ansatzpunkt.

    Vielen Dank an alle für Ihre Bemühungen ! 👍

    Viele Grüße

    Chrisitan



  • Artchi schrieb:

    Ui ui, hat MySQL keine Storedprocedures??? 😮

    Kommen afaik mit Verison 5, hilft MySql aber auch nix.

    MfG SideWinder



  • SciFi schrieb:

    Ich frage ja mit "SELECT * FROM..." ab und bekomme als Ergebnis alle Daten. Wenn ich jetzt selektiere mit von bis, habe ich bestimmt wieder das gleiche in Grün.

    du könntest es z.b. so machen

    # pseudo...
    last_id = -1;
    while (have rows) do
      SELECT * from table WHERE id > lastid ORDER BY id ASC LIMIT 1000
      while (have rows) do
        # insert query
        processed_ids =  row.id;
      end
    end
    

    hift das?



  • Ich denke schon, aber MySQL hat wohl Probleme mit der Menge an Daten die ich da rüberschaufel. Ich müsste dann noch den 1000 eine kleine Pause machen.
    Momentan suche ich noch nach INSERT Ergänzungen.



  • Wenn du Indizes verwendest bremsen die Inserts das System möglicherweise.
    Kannst du nicht vor den Inserts den Index löschen und ihn erst nach
    Beendigung ALLER Inserts neu erstellen.

    Ein andere Möglichkeit ist vielleicht die Verwendung von Transaktionen.
    Nur jeweils alle 1000 Inserts ein commit könnte dann auch helfen.



  • Danke für den Hinweis. Wenn das jetzt nicht klappen sollte, dann werde ich die Insert's in eine Datei schreiben und diese von der mysql.exe importieren lassen. Das ist zwar nicht die Lösung die ich gerne hätte, aber die andere ist wirklich zu langsam.



  • EDIT: murks



  • murks ?



  • SciFi schrieb:

    Wenn das jetzt nicht klappen sollte, dann werde ich die Insert's in eine Datei schreiben und diese von der mysql.exe importieren lassen. Das ist zwar nicht die Lösung die ich gerne hätte, aber die andere ist wirklich zu langsam.

    Und wieso soll's davon schneller werden?


Anmelden zum Antworten