WordPress Semmelstatz beschleunigen

Mittwoch, 12.1.2011, 07:19 > daMax

In letzter Zeit wurde mein Statistik-Plugin "Semmelstatz" quälend langsam. Leider wird es nicht weiter entwickelt, deshalb war keine Besserung in Sicht. Der Fiese Admin hat jedoch mit 2 Indizes und 3 optimierten Queries dem Plugin Beine gemacht. Tja, und da man ja nie weiß, wie lange so eine Website online bleibt, habe ich mir den Artikel direkt mal kopiert. Für die freundliche Genehmigung bedanke ich mich herzlich beim Fiesen Admin.


______________________

Falls noch jemand das gute alte Semmelstatz für seine Blog Statistiken benutzt und findet, dass die Anzeige der Statistiken im Admin Bereich zu lange dauert, dann sollte er ein wenig Hand anlegen. Mit nur wenigen Schritten ist Semmelstatz pfeilschnell.

Da ich selbst ein Gewohnheitstier bin und nur ungern auf neue Systeme umsteige wenn sich die alten bewährt haben, ist bei mir immer noch Semmelstatz im Einsatz, um Blog Statistiken erfassen zu können. Den Aufzeichnungen von Semmelstatz verdankt ihr die Suchbegriffe des Monats. ;-)

Problem ist allerdings, dass die Anzeige der Statistiken im Adminbereich von WordPress super langsam is,t wenn man erst einmal ein paar Einträge in der Datenbank hat. Da kann das schon mal 2 Minuten dauern. Viel zu lange!
Der Grund dafür sind sehr schlechte Datenbank Queries. Die Indizes werden z.B. nicht genutzt was bedeutet, dass MySQL jedes mal die gesamte Datenbank durchsuchen muss.

Durch ein paar Modifikationen der Abfragen lässt sich das ganze aber beschleunigen. Was vorher mehrere Minuten dauert geht dann in Sekunden.

Das ganze funktioniert bei Semmelstatz 3.1 und für 3.0.1, da sind die Namen der Aufrufe etwas anders. (statt $wbdb->XXX ist es $this->wpdb->xxx)
Sofern die Datenbankqueries bei äteren Semmelstatz Versionen die selben sind funktioniert es dort natürlich auch.

Die Änderungen werden in der Datei semmelstatz_func.php umgesetzt.

Die drei großen Flaschenhälse sind:

  • Die Statistik Anzeige für heute
  • Die Statistik Anzeige der letzten X Tage
  • Die Top 10 Beiträge

Lösung:

Statistik Anzeige für heute
In der Semmelstatz Tabelle einen Index auf das Feld “time” setzen.

In der Funktion sem_showTodayStatz() die Query

SELECT COUNT(ip) AS hits, COUNT(DISTINCT ip) AS visitors, COUNT(DISTINCT referer) AS referers, substring(time,1,10) AS date FROM ".$wpdb->statz." WHERE substring(time,1,10) = CURDATE() GROUP BY date

durch folgende Query ersetzen:

SELECT COUNT(ip) AS hits, COUNT(DISTINCT ip) AS visitors, COUNT(DISTINCT referer) AS referers, substring(time,1,10) AS date FROM ".$wpdb->statz." WHERE time >= CURDATE() GROUP BY date

Erklärung: Da time das Bedingungsfeld ist, braucht es einen Index, damit die Daten schneller beglichen werden können. Das Umschreiben im Query entfernt die Berechnung im Bedingungsteil (andernfalls nützt uns der Index nämlich nichts).

Statistik Anzeige der letzten x Tage
Benötigt ebenfalls einen Index auf time. Den haben wir ja oben schon gesetzt. Bleibt die Optimierung des MySQL Queries in der Funktion sem_showDailyStatz()

Folgende Query ist gegeben:

SELECT COUNT(ip) AS hits, COUNT(DISTINCT ip) AS visitors, COUNT(DISTINCT referer) AS referers, substring(time,1,10) AS date FROM ".$wpdb->statz." GROUP BY date ORDER BY time DESC LIMIT 0, ".$limit

Vor dem Query Aufruf muss noch folgende Zeile hinzugefügt werden:

$daylimit=$limit-1;

Und anschließend ersetzen wir die Query durch diese, die 8-10 mal schneller ist.

SELECT COUNT(ip) AS hits, COUNT(DISTINCT ip) AS visitors, COUNT(DISTINCT referer) AS referers, substring(time,1,10) AS date FROM ".$wpdb->statz." WHERE time>=CURDATE()-INTERVAL ".$daylimit." DAY GROUP BY date ORDER BY time DESC");

Erklärung: Die Original Query lädt zuerst die Statistiken aller Tage in der Tabelle und zeigt dann die ersten X davon an. Da uns die anderen gar nicht interessieren können wir der Datenbank die Mühe auch sparen und die zu verarbeitenden Zeilen auch gleich begrenzen und das tun wir mit der Ergänzung des heutigen Datums - des Limits.

Die Top 10 Beiträge
Index auf page in der Statz Tabelle setzen.

In der Funktion sem_showTopReads() die Query

SELECT post_title AS posttitle, post_name as postname, guid AS postid, COUNT(".$wpdb->statz.".page) AS count FROM ".$wpdb->posts.", ".$wpdb->statz." WHERE ".$wpdb->statz.".page = ".$wpdb->posts.".ID GROUP BY postid ORDER BY count DESC LIMIT 10

durch diese ersetzen, die aus einer 70 Sekunden langen Abfrage eine 2 Sekunden Abfrage macht

SELECT STRAIGHT_JOIN post_title AS posttitle, post_name as postname, guid AS postid, COUNT(".$wpdb->statz.".page) AS count FROM ".$wpdb->statz.", ".$wpdb->posts." WHERE ".$wpdb->statz.".page = ".$wpdb->posts.".ID GROUP BY page ORDER BY count DESC LIMIT 10");

Erklärung: Straight Join und die Reihenfolge der Tabellen in der Abfrage sind der Schlüsselpunkt. Zudem wird nun nach einem indexierten Feld gruppiert.

Vermutlich lassen sich die anderen Queries ebenfalls optimieren. Diese 3 waren aber die lahmsten. Die anderen nehme ich mir vielleicht auch mal vor, wenn sich dadurch noch starke Verbesserungen erzielen lassen.