Michael Schröpl: RAND() bei MySQL funktioniert nicht richtig

Beitrag lesen

Hi Florian M.,

Nun möchte ich, dass nach jedem "Refresh" des Browser ein zufälliges Zitat
aus der Datenbank ausgelesen wird.

nein, das möchtest Du nicht - denn diesen Zustand hast Du bereits.

Dies funktioniert nur teilweise, bzw. nicht zufriedenstellend.

Ich vermute, dies liegt zum Teil auch daran, daß Deine Aufgabenstellung in Wirklichkeit eben nicht "zufällige" Treffer haben will, sondern in erster Priorität ein bestimmtes Verteilungsverhalten im n-dimensionalen Raum wünscht und erst in zweiter Priorität die zufällige Auswahl.

Wenn Du die Wahrscheinlichkeit für aufeinanderfolgende identische Treffer kontrollieren willst, dann würde ich an Deiner Stelle vorschlagen, Dich vom Lotto-Modell inspirieren zu lassen und Kugeln aus einer Urne zu ziehen - ohne Zurücklegen. Also keine zufälligen Zitate, sondern zufällige Anordnungen der Liste sämtlicher Zitate.
Ich würde an Deiner Stelle ein Gedächtnis verwenden und darin speichern, welche Zitate im aktuellen "Durchgang" bereits "gezogen" wurden und welche noch nicht. In dem Moment, in welchem die Urne leer wird, füllst Du wieder alle Kugeln hinein. Auf diese Weise werden alle Kugeln gleich oft gezogen, es ist auch zufällig, in welcher Reihenfolge, aber es kommen nun keine Häufungen mehr vor.
Es kann immer noch passieren, daß die letzte Kugel aus Durchgang <n> identisch mit der ersten Kugel aus Durchgang <n+1> ist - diesen Sonderfall kannst Du aber gezielt abfragen und in diesem Falle ausnahmsweise doch mal eine Kugel zurücklegen.

Da Deine Aufgabenstellung jedoch im Web-Kontext dargestellt wurde, ist Dein Problem möglicherweise schwieriger. Wenn nämlich mehrere Anwender gleichzeitig Zitate aus Deinem Topf ziehen, kann es immer noch vorkommen, daß ein bestimmter Anwender nur einmal pro "Durchgang" an der Reihe ist und zufällig immer genau dasselbe Zitat angezeigt bekommt.
In diesem Falle müßtest Du _pro_Anwender_ eine Urne aufstellen - sprich: Du müßtest Deine Besucher identifizieren können (Login, Session-ID, in erster Näherung wäre auch die IP-Adresse ausnahmsweise ganz brauchbar).

Bedenke aber, daß die Verwaltung der Urnen dazu tendiert, ein Transaktionskonzept zu erfordern ... Du kannst eine wirklich schöne Lösung völlig ohne aufeinanderfolgende Duplikate bauen, wenn Du die richtigen Werkzeuge dafür einsetzt.
Aber das Geheimnis dabei besteht darin, Deine Anforderungen _exakt_ zu beschreiben. Daß "zufällig" in Deinem Fall nicht ausreicht, sollte Dir inzwischen bewußt geworden sein.

Es gibt übrigens eine triviale Methode, welche Deinem Besucher den Anschein des Zufalls bieten kann: Biete die Zitate einfach strikt sequentiell an! (Berechne die Position des nächsten Zitats aus der Position des vorherigen, die Du als CGI-Parameter zurück lieferst.)
Falls Deine Zitate nach einer erkennbaren Methodik (alphabetisch etc.) sortiert sein sollten, kannst Du dies durch eine entsprechende Abbildung verschleiern.

Beispiel für [1..10]: 6 - 9 - 2 - 5 - 8 - 1 - 4 - 7 - 10 - 3

f(x) = (3x + 3) mod 10

Wenn Du diese Position dem Besucher nicht explizit zeigst, dann sieht das für diesen schon ziemlich zufällig aus.

Wenn Deine Zitatesammlung eher statischer Natur ist, dann kannst Du auch einmalig eine beliebige Permutation aller Zitate auswürfeln und die erwürfelte Position als zusätzliche Tabellenspalte abspeichern.
Dann bekommt jeder Besucher Deine Zitate in einer für ihn undurchschaubaren, ursprünglich auch mal zufälligen, aber reproduzierbaren Reihenfolge zu sehen - und die Implementierung ist trivial (Du gibst "AND random_index = (N+1 mod Anzahl)" als zusätzliche Bedingung in der WHERE-Klausel an).

Man muß nicht ständig würfeln, um dem Besucher etwas zu zeigen, das zufällig aussieht. Man muß nur wissen, was man eigentlich erreichen will ...

Viele Grüße
      Michael

--
T'Pol: I apologize if I acted inappropriately.
V'Lar: Not at all. In fact, your bluntness made me reconsider some of my positions. Much as it has now.