Speicher-/Timeoutproblem
Harry
- datenbank
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
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.
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
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
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
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
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
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
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