Hi,
Hier ein paar Vorschläge:
Zunächst einmal solltest du prüfen, ob es auf die im join betroffenen Attribute (Spalten) der Tupel Relationen (ts, ts, ts ::) ) (Tabellen) Indexe in der Datenbank gibt. Hier ist die Syntax aus dem mySQL Handbook.
http://dev.mysql.com/doc/refman/5.0/en/create-index.html
Wenige updates sind aber ein klarer Indikator dafür, direkt einen Cache einzubauen.
Einen solchen Cache kannst du a) in der Anwendung und b) eventuell in der Datenbank implementieren (weiss nicht obs bei mySQL da so gute Features gibt).
In der Anwendung könntest du das Resultat in einer globalen Variable speichern. Sowas geht z.B. in Notes nicht, aber z.B. in servlet/jsp schon. Mit welcher Sprache greifst du darauf zu?
In Java könnte das sehr vereinfacht so aussehen:
Map cacheMap;
Data getData (String abfrageParameter) {
Data cacheObject = cacheMap.get(abfrageParameter);
if ( cacheObject== null) {
cacheObject = doRealQuery(abfrageParameter);
cacheMap.put(abfrageParameter, cacheObject);
}
return cacheObject;
}
Die Abfrage geht also zuerst gegen das anwendungsglobale cache Objekt und erst dann gegen die Datenbank, wenn dieses anwendungsglobale Cache-Objekt für den jeweiligen Abfrageparameter (falls es das überhaupt gibt) keinen Inhalt hat. (Map in Java ist sowas wie List in LotusScript).
Du kannst dann festlegen, dass der cache alle 12 Stunden oder so gelehrt wird, so dass aktuelle Daten irgendwann zum User gelangen.
Man kann das natürlich smarter machen, indem ein Prozess überprüft, ob sich das aktuelle Resultset von den Cache-Daten unterscheidet. Wenn nicht, wird der cache nicht gelöscht. Einfach zu managen sind solche Dinge nicht.
Bzgl. Datenbank-Caching existieren AFAIK in anderen Datenbanken bestimmte view-Typen, die das Ergebnis halten. Glaub aber nicht, dass es dies für MySql gibt.
Dafür kann dieses Feature möglicherweise interessant sein: (Query Cache) http://dev.mysql.com/doc/refman/5.0/en/query-cache.html
Zwischenstand:
Verbesserung von bisher 39 auf 10 Sekunden! :D
Wodurch:
- Ich hab das "böse" LIKE ersetzt durch BETWEEN - grenzt meinen Bereich weiter ein und scheint dadurch gleich drastisch performanter zu sein.
- Ich habe 2 neue Indexe auf die benutzten Spalte der Tabelle gesetzt
- Ein paar Drehungen an den Parametern query_cache_limit, query_cache_size
- Neuordnen der Tabelle durch "ALTER TABLE billing_data ORDER BY data_starttime, data_site"
Nun werde ich das ganze mal weiter beobachten und schauen was weiter passiert.
Ach ja, das Resultset hat eigentlich nur 15 Tupel, aber die für die Berechnung - das SUM und ROUND usw. - werden pro Monat 285000 Tupel durchforstet.
Edit:
Hier das "neue" Statement:
SELECT HIGH_PRIORITY
c.customer_name AS 'customer',
c.customer_freevolume AS 'freevolume',
c.customer_price_per_gb AS 'pricePerGB',
c.customer_currency AS 'currency',
ROUND(((SUM(d.data_recievedbytes) + sum(d.data_sendbytes))/1073741824),3) AS 'traffic',
ROUND(((SUM(d.data_recievedbytes) + sum(d.data_sendbytes))/1073741824),3) - c.customer_freevolume AS 'billedTraffic'
FROM billing_data d, billing_customer c
WHERE d.data_starttime BETWEEN '20051001000000' AND '20051031235959'
AND MID(d.data_site,3,3) = c.customer_short
GROUP BY c.customer_name