Harry: Speicher-/Timeoutproblem

Hallo,

ich habe ein kleines (Verständnis-)Problem:

Ich habe eine Tabelle, in der ca. 9 Millionen Datensätze drin sind, entspricht etwas über 4GB Daten.
In dieser Tabelle sind Logs gespeichert.

Um nun einen Visit zu berechnen, muß ich durch die Tabelle durchlaufen und in die richtige Reihenfolge bringen:

...order by ip, datum, zeit, .....

Das mache ich so:

while (@hitdata = $hits->fetchrow_array)
{
   Visitgrenze feststellen....
}

"Visitgrenze feststellen....":
Ich merke mir wichtige Werte wie IP usw.
Wenn ein neuer Wert auftaucht, so liegt ein neuer Visit vor, der alte gilt als abgeschlossen.

Aber das nur am Rande.

Nun das Problem an sich:
Mein Rechner hat nur 512MB. Der rödelt da stundenlang rum und sollte, wenn fertig, die Ergebnisse in einer anderen Tabelle speichern. Aber mittendrin bricht er ab. Ich weiß aber nicht, ob es einen Timeout gegeben hat oder der Speicher nicht reicht (die Platte hat noch genug Reserven!).

Nun bin ich hingegangen und habe das so umgebaut, daß ich mit limit arbeite, d.h. "limit $a, 10000" anwende und in einer Schleife die Funktion mit Parameter für $a aufrufe. Die Schleife erhöht $a dann immer um 10000.

Die Frage ist, ob es nicht anders geht, d.h. ob ich in der my.cnf irgendwas drehen muß/kann, was dann eine Berechnung ohne limit ermöglicht.

Laut meinem MySQL-Buch und der online-Doku. sollte ich mich darum nicht unbedingt kümmern müssen, weil MySQL selbständig swappt (,falls es ein Speicherproblem sein sollte).

Kann mir jemand einen Tipp geben?

Harry

  1. Halihallo Harry

    while (@hitdata = $hits->fetchrow_array)
    {
       Visitgrenze feststellen....
    }

    Du arbeitest also mit Perl. Ich hielte dies noch für
    erwähnungswürdig, zumal die Aussage, dass die Datenbank am Timeout
    Schuld ist nicht zwingend richtig sein muss...

    Mein Rechner hat nur 512MB. Der rödelt da stundenlang rum und sollte, wenn fertig, die Ergebnisse in einer anderen Tabelle speichern. Aber mittendrin bricht er ab. Ich weiß aber nicht, ob es einen Timeout gegeben hat oder der Speicher nicht reicht (die Platte hat noch genug Reserven!).

    Dann würde ich - oder besser: eigentlich immer - eine
    Fehlerbehandlung in das Programm integrieren.

    Nun bin ich hingegangen und habe das so umgebaut, daß ich mit limit arbeite, d.h. "limit $a, 10000" anwende und in einer Schleife die Funktion mit Parameter für $a aufrufe. Die Schleife erhöht $a dann immer um 10000.

    Du bekämpfst die Symptome, nicht aber die Krankheit; wenn mir diese
    kleine Analogie gestattet ist.

    Die Frage ist, ob es nicht anders geht, d.h. ob ich in der my.cnf irgendwas drehen muß/kann, was dann eine Berechnung ohne limit ermöglicht.

    mysql_use_result

    In Perl:
    my $sth = $dbh->prepare("SELECT ...", { 'mysql_use_result' => 1} );

    Dann werden die Daten auf dem Server gehalten und müssen explizit
    der Reihe nach über fetchrow_* eingelesen werden.

    Der Vorteil: Die Daten werden nicht im RAM gecached, bzw. wenn sie
    gecached werden, dann auf dem Server (MySQL-Server) und dieser
    Versteht es, wie man dies am einfachsten, effizientesten und
    speicherschonensten ablegt.

    Der Nachteil: Oftmals werden dadurch andere Prozesse geblockt
    und/oder ausgebremst.

    Viele Grüsse

    Philipp

    1. In Perl:
      my $sth = $dbh->prepare("SELECT ...", { 'mysql_use_result' => 1} );

      Dann werden die Daten auf dem Server gehalten und müssen explizit
      der Reihe nach über fetchrow_* eingelesen werden.

      Vielen Dank!
      Wie muß jetzt meine Schleife aussehen?
      Derzeit bekomme ich einen Fehler:
      DBD::mysql::st execute failed: Commands out of sync;  You can't run this command now at.....

      while (@hitdata = $hits->fetchrow_array)
      muß ich jetzt anders machen, oder?

      Harry

      1. Halihallo Harry

        Wie muß jetzt meine Schleife aussehen?

        Genau so, wie sie jetzt aussieht. Vorausgesetzt sie funktionierte
        vorher.

        Derzeit bekomme ich einen Fehler:
        DBD::mysql::st execute failed: Commands out of sync;  You can't run this command now at.....

        http://dev.mysql.com/doc/mysql/de/commands-out-of-sync.html

        $sth immer mit $sth->finish() beenden, bevor eine neue Abfrage ge-
        startet wird.

        Aufgrund des Fehlers gehe ich davon aus, dass du in der While-
        Schleife noch andere Queries in der Datenbank absetzt...

        Das Problem ist, dass mysql nur einen Server-Cache pro
        Verbindungskennung anlegt. Sprich: Es kann zur selben Zeit nur einen
        mysql_use_result-Query bearbeitet werden und dieser schliesst IMO
        sogar mysql_store_result-Queries aus.

        Die Lösung:
        Entweder du kannst den Programmfluss so abändern, dass nur ein
        aktives Statement zur selben Zeit bearbeitet wird.
        Oder du öffnest eine zweite Verbindung zur Datenbank
        (my $dbh2=DBI->connect(...)) und setzt dort die Queries innerhalb
        der while-Schleife ab.

        Also:

        my $dbh = DBI->connect(...);
        my $dbh2= DBI->connect(...);

        my $sth = $dbh->prepare(..., { mysql_use_result => 1 });
        $sth->execute();
        while ( my @row = $sth->fetchrow_array() ) {
            # do sth with @row
            my $sth2 = $dbh2->prepare('other_query');
            $sth2->execute();
        }

        while (@hitdata = $hits->fetchrow_array)
        muß ich jetzt anders machen, oder?

        Nein.

        Viele Grüsse

        Philipp

        1. Hi,

          Die Lösung:
          Entweder du kannst den Programmfluss so abändern, dass nur ein
          aktives Statement zur selben Zeit bearbeitet wird.
          Oder du öffnest eine zweite Verbindung zur Datenbank
          (my $dbh2=DBI->connect(...)) und setzt dort die Queries innerhalb
          der while-Schleife ab.

          Also:

          my $dbh = DBI->connect(...);
          my $dbh2= DBI->connect(...);

          Du hast mir sehr geholfen!!!
          Das war das Problem.
          Ich habe in der Schleife mit der gleichen Verbindung nochmal eine Abfrage gestartet.

          Vielen Dank!!!!!!!!

          Harry

          1. Halihallo Harry

            Du hast mir sehr geholfen!!!

            Das freut mich, danke für dein Feedback.

            Das war das Problem.

            und das Problem des Timeouts/Speichers ist dadurch auch gelöst?

            Viele Grüsse

            Philipp

            1. Hi,

              Du hast mir sehr geholfen!!!

              Das freut mich, danke für dein Feedback.

              normal, oder?

              Das war das Problem.

              und das Problem des Timeouts/Speichers ist dadurch auch gelöst?

              Sieht so aus! Aber das läuft jetzt ein paar Stunden, wenn nicht Tage....
              Ich bin gespannt.

              Gruß
              Harry

              1. Halihallo Harry

                Du hast mir sehr geholfen!!!
                Das freut mich, danke für dein Feedback.
                normal, oder?

                Halte ich eigentlich auch für selbstverständlich, aber viele andere
                Fragesteller haben hier offenbar eine andere Ansicht :-(

                Viele Grüsse

                Philipp