Pradeep Adigas erster Vorschlag, ORDER BY NEWID()
, ist gut und etwas, das ich in der Vergangenheit aus diesem Grund verwendet habe.
Seien Sie vorsichtig mit der Verwendung von RAND()
– in vielen Kontexten wird es nur einmal pro Anweisung ausgeführt, so dass ORDER BY RAND()
keine Auswirkungen hat (da Sie für jede Zeile dasselbe Ergebnis aus RAND() erhalten).
Zum Beispiel:
SELECT display_name, RAND() FROM tr_person
gibt jeden Namen aus unserer Personentabelle und eine „zufällige“ Zahl zurück, die für jede Zeile dieselbe ist. Die Zahl variiert jedes Mal, wenn Sie die Abfrage ausführen, ist aber jedes Mal für jede Zeile gleich.
Um zu zeigen, dass dies auch bei RAND()
in einer ORDER BY
-Klausel der Fall ist, versuche ich Folgendes:
SELECT display_name FROM tr_person ORDER BY RAND(), display_name
Die Ergebnisse sind immer noch nach dem Namen geordnet, was darauf hindeutet, dass das frühere Sortierfeld (das, von dem erwartet wird, dass es zufällig ist) keine Auswirkung hat und vermutlich immer denselben Wert hat.
Die Sortierung nach NEWID()
funktioniert jedoch, denn wenn NEWID() nicht immer neu bewertet würde, wäre der Zweck von UUIDs nicht mehr gegeben, wenn viele neue Zeilen in einer Statistik mit eindeutigen Bezeichnern als Schlüssel eingefügt werden, so dass:
SELECT display_name FROM tr_person ORDER BY NEWID()
die Namen „zufällig“ sortiert werden.
Andere DBMS
Das obige gilt für MSSQL (zumindest 2005 und 2008, und wenn ich mich recht erinnere auch 2000). Eine Funktion, die eine neue UUID zurückgibt, sollte in allen DBMSs NEWID() ist unter MSSQL jedes Mal ausgewertet werden, aber es lohnt sich, dies in der Dokumentation und/oder durch eigene Tests zu überprüfen. Das Verhalten anderer Funktionen mit beliebigem Ergebnis, wie z.B. RAND(), ist wahrscheinlich von DBMS zu DBMS unterschiedlich, also überprüfen Sie auch hier die Dokumentation.
Außerdem habe ich gesehen, dass die Reihenfolge von UUID-Werten in einigen Kontexten ignoriert wird, da die DB annimmt, dass der Typ keine sinnvolle Reihenfolge hat. Wenn Sie feststellen, dass dies der Fall ist, müssen Sie die UUID in der Ordnungsklausel explizit in einen Stringtyp umwandeln oder eine andere Funktion wie CHECKSUM()
in SQL Server verwenden (dies kann auch zu einem kleinen Leistungsunterschied führen, da die Sortierung auf einem 32-Bit-Wert und nicht auf einem 128-Bit-Wert erfolgt, aber ob der Vorteil davon die Kosten für die Ausführung von CHECKSUM()
pro Wert überwiegt, müssen Sie selbst testen).
Nebenbemerkung
Wenn Sie eine willkürliche, aber einigermaßen wiederholbare Reihenfolge wünschen, ordnen Sie nach einer relativ unkontrollierten Teilmenge der Daten in den Zeilen selbst. Zum Beispiel werden die Namen in einer willkürlichen, aber wiederholbaren Reihenfolge zurückgegeben:
Willkürliche, aber wiederholbare Ordnungen sind in Anwendungen nicht oft nützlich, können aber beim Testen nützlich sein, wenn Sie einen Code mit Ergebnissen in verschiedenen Ordnungen testen wollen, aber in der Lage sein wollen, jeden Durchlauf mehrmals auf die gleiche Weise zu wiederholen (um durchschnittliche Timing-Ergebnisse über mehrere Durchläufe zu erhalten, oder um zu testen, dass eine Korrektur, die Sie am Code vorgenommen haben, ein Problem oder eine Ineffizienz beseitigt, die zuvor durch einen bestimmten Eingabe-Ergebnissatz hervorgehoben wurde, oder einfach um zu testen, dass Ihr Code „stabil“ ist, indem er jedes Mal das gleiche Ergebnis liefert, wenn die gleichen Daten in einer bestimmten Reihenfolge gesendet werden).
Dieser Trick kann auch verwendet werden, um willkürlichere Ergebnisse von Funktionen zu erhalten, die keine nicht-deterministischen Aufrufe wie NEWID() in ihrem Körper erlauben. Auch dies ist nicht etwas, das in der realen Welt oft nützlich sein wird, aber es könnte nützlich sein, wenn eine Funktion etwas Zufälliges zurückgeben soll und „zufällig“ gut genug ist (aber achten Sie auf die Regeln, die bestimmen, wann benutzerdefinierte Funktionen ausgewertet werden, d.h. in der Regel nur einmal pro Zeile, oder Ihre Ergebnisse könnten nicht das sein, was Sie erwarten/erfordern).
Leistung
Wie EBarr anmerkt, kann es bei jeder der oben genannten Möglichkeiten zu Leistungsproblemen kommen. Bei mehr als ein paar Zeilen ist es fast garantiert, dass die Ausgabe in die tempdb gespooled wird, bevor die angeforderte Anzahl von Zeilen in der richtigen Reihenfolge zurückgelesen wird, was bedeutet, dass selbst bei der Suche nach den Top 10 ein vollständiger Index-Scan (oder schlimmer noch, ein Table-Scan) zusammen mit einem riesigen Schreibblock in die tempdb erfolgt. Daher ist es, wie bei den meisten Dingen, von entscheidender Bedeutung, einen Benchmark mit realistischen Daten durchzuführen, bevor man dies in der Produktion einsetzt.