Auf unserem Rootserver laufen mittlerweile einige Domains. Ein paar Anwendungen sind datenbanklastig.
Ich wunderte mich eigentlich schon länger, das https://Zockertown.de/s9y/ viel langsamer als http://Zockertown.de/ ist. Die index.html auf der Mainsite kommt praktisch augenblicklich, die serendipityseite brauchte mittlerweile im Mittel schon 5 Sekunden, manchmal auch viel länger, um überhaupt mit dem Seitenaufbau zu beginnen. Ich habe mich nun in den letzten Tagen etwas näher damit auseinandergesetzt. Ich bin kein Mysql DB Spezialist, aber als alter Informix Hase sollte da doch was zu machen sein.
Da auf dem Rootserver vielen Anwendungen gleichzeitig laufen habe ich nach einer Möglichkeit gesucht, die ausgefführten SQL-Statements mitzuloggen, um daraus weitere Erkenntnisse zu ziehen. Zuerst musste ich herausfinden, welcher User der Mysql admin ist. Da der Rootserver plesk installiert hat, haben wir die Datenbanken auch damit angelegt. Tatsächlich wird der DBAdmin der selbe User, den man für Plesk verwendet. Aber das am Rande.
Die verwendete mysql Version ist 4.1.10. Die Konfiguration bezieht der mysqld aus /etc/my.cnf
Es gibt zwei Wege zum Einschalten der Query Protokollierung, die erste, hier auskommentierte Variante logt alle Queries, was mir bei der Menge der Anfragen nicht sinnvoll erschien.
#set-variable = log=On
set-variable = log_slow_queries=On
set-variable = long_query_time=4
Die zweite Variante ist das Protollieren der sogenannten slow-queries, das mir sehr geeignet erschien und sich als sehr effektive Methode herausgestellt hat.
On heißt übrigens nicht: Schalter auf ON, sondern Name des Logfiles, dämlicher Name, ich weiss, ist aber wenigstens kurz

In dem oben genannten Beispiel steht
long_query_time=4 bedeutet also, logge alle Queries, die mindestens 4 Sekunden dauern.
In diversen Publikationen wird als Beispiel immer 10 Sekunden genommen, das halte ich beieiner Web-Anwendung allerdings für viel zu lang. Eine performante Anwendung, sei es nun Blog, Wissensdatenbank oder nur eine Lanparty Statistikseite darf sich max. 3 Sekunden erlauben, dann muss sich spätestens was auf dem Monitor des Anwenders tun. Rechnet man noch eine Sekunde für das Netz hinzu, dann verbleiben 2 Sekunden für die Datenbank. Ich habe im ersten Schritt bewusst den Zähler auf 4 gesetzt, weil ich sonst von der Menge der Ergebnisse erschlgen worden wäre. Doch nun genug von dem Vorgeplänke, zur Sache Schätzchen.
Ich beschreibe erst die Serendipity betreffenden Issues, weil dir mir am wichtigsten waren. Zwei Beispiele aus dem Log:
# Time: 060521 0:50:15
# User@Host: xxx[xdb] @ localhost []
# Query_time: 15 Lock_time: 0 Rows_sent: 0 Rows_examined: 93022
SELECT count(sessID) FROM serendipity_visitors
WHERE '905a4484485' = sessID GROUP BY sessID;
# Time: 060521 0:55:14
# User@Host: xxx[xxdb] @ localhost []
# Query_time: 4 Lock_time: 0 Rows_sent: 0 Rows_examined: 93032
SELECT count(sessID) FROM serendipity_visitors
WHERE 'e9302343949bf' = sessID GROUP BY sessID;
Wenn so eine fuer eine Datenbank lächerlich einfache Anfrage 15 Sekunden dauert, dann ist da was faul. Um das zu analysieren startete ich phpmyadmin. Die Tabelle serendipity_visitors gehört zu einem plugin, welches die Anzahl der Besucher, die in letzter Zeit die Site besucht haben, zählt und anzeigt. Die Anfragen in dem Beispiel schauen einfach nur nach, wieviel User mit der gleichen sessionid (hier verkürzt dargestellt) in der Tabelle eingetragen sind. Der weitere Ablauf braucht uns nicht weiter zu interessieren. Gemacht wird das zählen mit dem SQl Befehl count, der als Argument eine Spalte erwartet. Was macht die Datenbank nun mit einem solchen Befehl? Genau, sie schaut nun alle 93000 Eintrage durch und vergleicht die sessionid mit dem Abfragestring in der WHERE Clause. Das Dumme ist nur, in der Tabelle sind ja auch noch andere Spalten, wenn ich mich nicht verzählt habe, dann sind 576 Bytes pro Eintrag gespeichert, Da davon einige Felder auch varchar sind gehe ich mal von 400 Byte Platz für jeden Eintrag aus. Mal 93000 sind etwa 37 MB Daten. Die zu durchsuchen dauert natürlich etwas ...
Aber die Datenbankhersteller haben mitgedacht und sich so sinnvolle Dinge wie index einfallen lassen. Wenn nämlich ein Index exitiert, ist der immer alfabetisch sortiert, die Datenbank hat mit sehr wenigen Zugriffen die passenden Stellen ausgelesen. Der Geschwindigkeitsfaktor ist dadurch enorm, durchschnittlich dauert so eine Anfrage nun nur noch ein paar tausendstel Sekunden. Mal sehen, hhm nein, kein index auf sessionid gesetzt. Aber das habe ich gleich nachgeholt, und siehe da, zumindestens diese Query taucht fortan nicht mehr in dem Log auf. Bei anderen Queries ging ich genau nach dem selben Prinzip vor. Als Faustformel braucht man nur beachten, das alle Vergleiche auf =, < oder > immer über einen Index schneller erledigt werden können als durch eine sequenzielle Suche. Nur in ganz kleinen Tabellen mag ein Index mal kontraproduktiv sein. Ich fand noch in serendipity_entries, dort fehlte der Index auf authorid.
Diese beiden Maßnahmen haben bereits zu einer spürbaren Verbesserung der Antwortzeitverhaltens von Zockertown geführt.
(wird fortgesetzt)
"Addons" oder "Mods" für Webanwendungen ala phpbb, vbulletin, oder neuerdings auch wp oder s9y sind häufig ein Problem. Nicht nur für die Performance sondern auch für Sicherheit. Man sollte alles was man installiert, zumindest mal grob überfliegen...
Ja, stimmt auffallend
siehe auch meiner weiteren Dokumentation, da wirds dann richtig lustig 