Hi Sven,
danke für die lange Antwort, ich muß mich mich da erstmal komplett durchworschteln und da alles ausprobieren...
Moin!
Eine Tabelle ist jedoch inzwischen so groß, daß sie von der Festplatte gelesen werden muß. Dauer dieser Aktion etwa 4sek !!!
Alle Datenbankdaten werden typischerweise von Festplatte gelesen - die häufig benutzten kommen aber vielleicht auch aus dem Cache.
Das mit den Cache stimmt nur teilweise, nämlich dann, wenn die Query absolut identisch ist zu einer Query davor,
http://dev.mysql.com/doc/refman/4.1/en/query-cache-how.html
Wie das mit dem Lesen und Schreiben auf Platte ist kann ich nicht genau sagen. Ich glaube irgendwo gelesen zu haben, daß bei kleinen Tabellen die Tabelle im Speicher bleibt und Updates auf die Platte geschrieben werden. Es wird dann aber nicht die Tabelle geändert, sondern ein Änderungsanhang an der Tabelle anhgehängt.
Das das Problem an der Festplatte liegt, da bin ich mir fast sicher. Weil ich meine Probleme löse, wenn ich eine große Menge an Datensätzen aus dieser Tabelle lösche und die Tabelle optimiere.
Nur sowas klappt nicht auf Dauer.
Wärenddessen laufen die anderen Anfragen an den Server munter weiter.
Nun passiert anscheinend folgendes:
Jede neue Anfrage wird soweit bearbeitet, bis die erste DB-Abfrage kommt. Die Abfrage wird auf eine Queue geschoben und wird bei Bedarf abgearbeitet.Kommen jedoch zuviele Anfragen, und auch zuviele von der großen Tabelle, dann läuft die Queue anscheinend über.
In diesem Moment kommt dann der Fehler 'more than max_data_connections'...
Nein, die Queue läuft nicht über.
MySQL hat, genau wie der Apache-Webserver auch, eine maximale Zahl an Clients, die gleichzeitig bedient werden können.
Offenbar ist die Zahl der Clients, die MySQL bedienen kann, kleiner als die Zahl, die Apache bedienen kann. Es kann also passieren, dass ein Browser eine Anfrage schickt, die nicht beantwortet werden kann, weil MySQL schon komplett ausgelastet ist - verbindungsmäßig gesehen.
Da hast du also zwei Stellschrauben: Entweder reduzierst du die Zahl der im Apache möglichen parallelen Prozesse (oder Threads o.ä., je nachdem, was du da benutzt), oder du erhöhst die Zahl der in MySQL erlaubten parallelen Connections - am Ende sollten die beiden Zahlen mindestens identisch sein, MySQL sollte tendentiell vielleicht sogar ein paar Connections mehr erlauben.
Die zweite Möglichkeit ist natürlich, deine Querys zu optimieren. Kritisch sind in diesem Zusammenhang alle schreibenden Operationen, weil dazu immer Lesezugriffe auf die betroffene Tabelle gesperrt werden müssen (eventuell auch nur die betroffenen Spalten, je nach Version und DB-Möglichkeiten).
Schreiboperationen wären also ein Ziel der Optimierungen. Leseoperationen selbst sollten, wo immer möglich, einen Index benutzen.
Und wenn es möglich ist, kann man die Nutzung des Index auch nochmal genauer untersuchen und unter Umständen optimieren.
Anscheinend ist es so, daß der Apache-Server die Prozesse wirklich parallel abarbeiten kann, wärend der DB-Server nach dem FIFO-Prinzip arbeitet.
Meist merke ich ja, wenn die Datenbank anfängt in die Kniee zu gehen, die Abfragen dauern dann immer länger, bis zu etwa 30 sekunden.
In dieser Zeit kann ich aber reine HTML-Seiten so schnell wie immer vom Server runterladen.
Indezes sind eigentlich ausgereizt, wo fast nur lesend zugegriffen wird habe ich schon 2-3 Indezes.
Bei den meisten Queries wird ja über die ID eines oder zweier User gearbeitet, das ist fast schon straight forward dort den richtigen Index zu finden.
Ich vermute mal, daß wenn man jede Seite um eine halbe Sekunde in der Verarbeitung verzögert, dann läßt man den DB-Server genügend Zeit, alle Queues abzuarbeiten. Der User merkt davon kaum was.
Das ist, wie oben gesagt, nicht dein Problem. Abgesehen davon, dass man die Organisation der Abarbeitung in der DB sowieso nicht organisieren kann und es auch nicht tun sollte, kannst du Schreib-Querys von deiner Seite aus eigentlich nur als unwichtiger markieren, so dass diese nicht sofort, sondern erst später ausgeführt werden, wenn die DB dazu Zeit findet. Bei Leseoperationen kannst du hingegen Querys nur als wichtiger kennzeichnen.
Es gibt die Möglichkeit, schreibende Zugriffe zu verzögern (LOW_PRIORITY, DELAYED), in meinem Fall wäre das sogar anwendungslogisch kein Problem (es wäre eins, wenn zB die nächste Seite in einer Handlungsfolge auf die geänderte Tabelle aufbauen würde).
Jedoch treten meine Probleme schon beim reinen Lesen auf.
Meine Frage also, kann man dem Server (in meinem Fall dem Apache) mitteilen, daß er jede Abfrage erstmal eine halbe Sekunde auf eine Queue schieben soll, und dann erst mit der Auswertung beginnen ?
Im Grunde genommen wäre damit ja nichts gewonnen! Diese Verzögerung könntest du selbst ja auch dadurch hinkriegen, dass du ein Javascript in den Link einbaust, dass das Linkauslösen um eine halbe Sekunde verzögert. Oder den Benutzer anweisen, einfach eine halbe Sekunde später zu klicken.
Das Resultat: Alles passiert eine halbe Sekunde später - und funktioniert genauso wenig. :)
- Sven Rautenberg