So heute geht es mal darum ein wenig die MySQL Datenbank
Anweisungen zu optimieren. Die Ladegeschwindigkeit
von MySQL Befehlen kann über die INSERT
DELAYED und die UPDATE LOW_PRIORITY positive
Geschwindigkeitsschübe bei der Webseite veranlassen
und die Last des MySQL-Servers sehr reduzieren.
Das Problem ist, wenn mehrere hundert Zugriffe gleichzeitig
auf eine Tabelle erfolgen, können diese sich
gegenseitig stören: Da UPDATE und INSERT bei
MySQL eine höhere Priorität als SELECT Anweisungen
haben, aber mehr Zeit in Anspruch nehmen und zudem SELECT Anweisungen
blockieren, bis sie fertig ausgeführt sind,
kann dies bei einem hohem Besucheraufkommen zu einem
verlangsamten Seitenaufbau der Website führen
oder sogar den Server überlasten.
Deshalb gibt es die Möglichkeit statt dessen
unwichtige UPDATE und INSERT warten
zu lassen, bis die SELECT Anweisungen durchgeführt
worden sind. Wenn Sie die UPDATE und INSERT Anweisungen
auf Ihrer Website durchgehen, werden Sie mit großer
Wahrscheinlichkeit welche finden, die nicht sofort
ausgeführt werden müssten.
Umsetzen können Sie dies mit INSERT DELAYED und UPDATE
LOW_PRIORITY. Zur Erläuterung werden
dafür hier folgende Anweisungen verwendet,
wie sie zum Beispiel in einem Onlineshop vorkommen
könnten, in dem User selbst Artikel anbieten
(unter der Bedingung, dass der User darüber
informiert wird, dass die Übernahme der Eingaben
sich verzögern kann).
- Änderung eines angebotenen Artikels: UPDATE
`artikeltab` SET `name`='eingabename', `preis`='eingabepreis'...;
- Einstellen eines Artikels: INSERT INTO `artikeltab` (`name`,
`preis`...) VALUES ('eingabename', 'eingabepreis'...);
Beachten Sie bitte, dass es sich hierbei lediglich
um Beispiele handelt und Sie selbst erwägen
müssen, ob das Verzögern gerade dieser UPDATE und INSERT Anweisungen
für Ihre eigene Website in Frage kommt oder
nicht. So können Sie die Ausführung solcher
Anweisungen zurückstellen:
Mit UPDATE LOW_PRIORITY wird ein Datensatz
erst aktualisiert, wenn niemand mehr auf die betroffene
Tabelle zugreift. Dazu müssen Sie Ihre UPDATE Anweisungen
folgendermaßen umändern:
Vorher: UPDATE `artikeltab` SET `name`='eingabename',
`preis`='eingabepreis'...;
Nachher: UPDATE LOW_PRIORITY `artikeltab`
SET `name`='eingabename', `preis`='eingabepreis'...;
Sie sollten dabei beachten, dass LOW_PRIORITY den
Ablauf des PHP Scripts behindern kann, da mysql_query() erst
einen Rückgabewert bekommt, sobald das UPDATE durchgeführt
wurde. Dies kann man umgehen, indem man das UPDATE im
PHP Script an den Schluss setzt.
Es gibt auch die Möglichkeit anstatt die Priorität
von UPDATE herunter zu setzen, die der wichtigen SELECT Anweisungen
herauf zu setzen. Dies kann jedoch zum einen mehr
Arbeit sein, da es meistens mehr SELECT Anweisungen
gibt und ein Suchen/Ersetzen im Quellcode nicht ausreicht,
weil Sie für jede einzeln entscheiden müssen,
ob es sinnvoll ist HIGH_PRIORITY einzusetzen
oder nicht. Zum anderen, was noch wichtiger ist,
könnten auf diese Weise auch wichtige UPDATE und INSERT Anweisungen
zurückgestellt werden.
Wenn Sie diese Möglichkeit dennoch verwenden
wollen, dann müssen Sie Ihre Anweisungen wie
folgt ändern:
Vorher: SELECT `id`,`name`... FROM `artikeltab`;
Nachher: SELECT HIGH_PRIORITY `id`,`name`...
FROM `artikeltab`;
Noch ein kleiner Powertipp in diesem Sinne, verwenden
Sie bei allen SELECT Anweisungen den Namen
der jeweiligen Spalte. Verzichten Sie auf Abfragen
mit SELECT * ...
Auch für INSERT gibt es LOW_PRIORITY,
aber hier ist INSERT DELAYED von Vorteil.
Die Anweisung wird dabei sofort ausgeführt und
der neue Datensatz in eine Warteschlange geschrieben.
Dadurch bekommt mysql_query() des PHP Scripts immer
sofort den Wert true zurück geliefert und wird
somit nicht wie oben beschrieben behindert. Zudem
werden die Anweisungen aus der Warteschlange dann
gebündelt (also schneller als Einzelanweisungen)
abgearbeitet, sobald es keine anderen Zugriffe mehr
auf die betroffene Tabelle gibt.
Hierzu müssen Sie Ihre INSERT Anweisungen
folgendermaßen ändern:
Vorher: INSERT INTO `artikeltab` (`name`, `preis`...)
VALUES ('eingabename', 'eingabepreis'...);
Nachher: INSERT DELAYED INTO
`artikeltab` (`name`, `preis`...) VALUES ('eingabename',
'eingabepreis'...);
Hierbei sollten Sie beachten, dass INSERT DELAYED langsamer
ist als normale INSERT Anweisungen, da immer
erst geprüft werden muss, ob noch andere Zugriffe
auf die Tabelle laufen. Zudem müssen Ihre Tabellen
mit dem MyISAM-, MEMORY- oder ARCHIVE-Speicher-Engine
angelegt worden sein um diese Anweisung durchzuführen. Bei INSERT ... SELECT und INSERT ... ON
DUPLICATE KEY UPDATE Anweisungen funktioniert
das DELAYED nicht, da es vom Server ignoriert
wird.
Damit die Warteschlange nicht zuviel Speicherplatz
blockiert, wird über die Variable delayed_queue_size
festgelegt, wieviele Datensätze in der Warteschlange
stehen dürfen. Zusätzliche INSERT DELAYED Anweisungen
müssen dann warten, bis wieder genügend
Platz in der Warteschlange zur Verfügung steht.
In diesem Fall muss auch das PHP Script auf die Rückmeldung
warten. Wenn Sie die betreffende Tabelle mit LOCK
TABLES gesperrt haben, dann kommt es bei INSERT
DELAYED zu einer Fehlermeldung.
Wenn Sie die oben aufgeführten Anweisungen
verwenden, sollten Sie immer bedenken, dass die auf
diese Weise hinzugefügten oder geänderten
Daten, erst angezeigt werden können, sobald
die jeweiligen Anweisungen abgearbeitet worden sind.
Wenn immer wieder andere Anweisungen herein kommen,
kann es unter Umständen sehr lange dauern, bis
die wartenden ausgeführt werden. Also verwenden
Sie diese nur, wenn Sie sich sicher sind, dass Sie
die betroffenen Daten nicht direkt benötigen. Zudem
können die Daten verloren gehen, falls der Server
abstürzt, bevor die Anweisungen ausgeführt
wurden.
Um zu sehen was der Mysql Server überhaupt macht,
kann man mit SHOW FULL PROCESSLIST die gesamte Processlist
sich ausgeben lassen. Dies hilft um langsame Abfragen
zu finden. In diesem Sinne viel Spaß beim optimieren
eurer MySQL Abfragen. Habt Ihr noch Fragen, steht
euch unser Forum zur
Verfügung.