molily: performante Verteilungsstatistik

Beitrag lesen

Hallo,

In http://aktuell.de.selfhtml.org/weblog/aufloesung-viewport habe ich ein Script beschrieben, dass mithilfe von JavaScript Viewport-Breiten in eine PostgreSQL-Datenbank einträgt.

Ich habe also beliebige Zahlen zwischen 0 und ichweißnichtwieviel in der Datenbank. Daraus will ich letztlich eine solche Statistik erstellen:
http://aktuell.de.selfhtml.org/weblog/files/2006-04-viewport-gesamt-ausschnitt.png
Das ist so zu lesen: 78,9% aller Zahlen sind unter oder gleich 1000.

Jetzt frage ich mich, wie ich die Zahlen für eine solche Statistik performant berechne mit möglichst wenig Datenbankaufwand.

Zwei Methoden habe ich gefunden:

1. Ich mache (vereinfacht):

SELECT innerwidth, count(id) as summe FROM hits GROUP BY innerwidth ORDER BY summe DESC

So bekomme ich eine Tabelle, in der drinsteht, wieviele Einträge (summe) es zu der vorkommenden Zahl (innerwidth) gibt.

Dann durchlaufe ich alle Zeilen des Ergebnisses, runde die innerwidth auf die nächste Zehnerstelle auf. Dann lege ich ein Arrayelement mit dieser Zahnerstelle als Index an. In dieses Arrayelement schreibe ich dann die Anzahl der Datensätze (summe) bzw. addiere sie. Z.B. $array[$gerundete_breite] += $hits; (Pseudocode).

Gleichzeitig addiere ich die summe zu einer Totalsumme.

So komme ich z.B. zu einem solchen Array (willkürlich):

400 => 25
620 => 543
830 => 134
1000 => 7854

Daraus lege ich dann einen Array an, in dem die kumultativen Zahlen in Zehnerschritten drinstehen:

400 => 25
410 => 25
...
620 => 568
...
830 => 702
...
1000 => 8556

Daraus kann ich dann Prozentwerte berechnen ausgehend von der Totalsumme (total / total - wert):

400 => 0.9974287050023375409
...
620 => 0.933613838242169238
usw.

Vorteil dieser Methode: Sie ist schnell und kommt mit einer Datenbankabfrage aus.
Nachteil: Ich blicke nicht ganz durch, ob ich meine Berechnungen wirklich aussagen: Soundsoviel Prozent haben eine innerwidth kleiner gleich x.

2.

Ich hole die Summe aller relevanten Zeilen aus der Datenbank.
Ich hole den größten innerwidth-Wert aus der der Datenbank.

Ich laufe von 0 in Zehnerschritten bis zum größten innerwidth-Wert und mache immer wieder:

SELECT count(id) as summe FROM hits WHERE innerwidth <= $Breite;

Das Ergebnis schreibe ich jeweils in einen Array, daraus erstelle ich dann direkt die kumulative Prozent-Statistik.

Vorteil dieser Methode: Sie scheint mir präziser. Ich bekomme andere Werte als bei der anderen. (Ja, seltsam, ich werde das nochmal untersuchen.)
Nachteil: Ich laufe in Zehnerschritten von 0 bis z.B. 2480 und führe immer wieder diese Abfrage aus. Das dauert ewig, sodass ich das Script schonmal gar nicht mehr über HTTP aufrufen kann, sondern nur noch auf der Kommandozeile.

Jetzt suche ich eine Möglichkeit, wie ich das ganze besser lösen kann. Ist es irgendwie möglich, diese Rechnerei die Datenbank-Software übernehmen zu lassen? Ich würde gerne weder eine Pseudo-Summenstatistik abfragen, mit der ich dann noch weiterrechnen noch, noch eine echte Summenstatistik, die hunderte Abfragen benötigt und 130 Sekunden läuft.

Gibts da irgendwelche eleganten Möglichkeiten? Vielleicht eine SQL-Query die mir annähernd direkt meine gewünschte Statistik ausgibt? Ich bin völlig PostgreSQL-unerfahren und ansonsten kenne ich auch nur MySQL oberflächlich.

Mathias