Pierwsza sugestia Pradeepa Adigi ORDER BY NEWID()
jest w porządku i z tego powodu korzystałem w przeszłości.
Zachowaj ostrożność przy użyciu RAND()
- w wielu kontekstach jest wykonywany tylko raz na instrukcję, więc nie ORDER BY RAND()
przyniesie żadnego efektu (ponieważ otrzymujesz taki sam wynik z RAND () dla każdego wiersza).
Na przykład:
SELECT display_name, RAND() FROM tr_person
zwraca każde nazwisko z naszej tabeli osób i „losową” liczbę, która jest taka sama dla każdego wiersza. Liczba zmienia się przy każdym uruchomieniu zapytania, ale jest taka sama dla każdego wiersza za każdym razem.
Aby pokazać, że to samo ma miejsce w przypadku RAND()
stosuje się w ORDER BY
punkcie, próbuję:
SELECT display_name FROM tr_person ORDER BY RAND(), display_name
Wyniki są nadal uporządkowane według nazwy wskazującej, że wcześniejsze pole sortowania (to, które ma być losowe), nie działa, więc przypuszczalnie zawsze ma tę samą wartość.
Porządkowanie według NEWID()
działa, ponieważ jeśli NEWID () nie zawsze był ponownie oceniany, cel UUIDs zostałby zepsuty podczas wstawiania wielu nowych wierszy w jednej pozycji z unikatowymi identyfikatorami, ponieważ klucz:
SELECT display_name FROM tr_person ORDER BY NEWID()
nie zamówić nazw „losowo”.
Inne DBMS
Powyższe odnosi się do MSSQL (przynajmniej 2005 i 2008, i jeśli dobrze pamiętam również 2000). Funkcja zwracająca nowy UUID powinna być oceniana za każdym razem we wszystkich DBMS-ach NEWID () znajduje się w MSSQL, ale warto to zweryfikować w dokumentacji i / lub przez własne testy. Zachowanie innych funkcji o dowolnym wyniku, takich jak RAND (), jest bardziej prawdopodobne, że różnią się między DBMS, więc ponownie sprawdź dokumentację.
Widziałem też, że porządkowanie według wartości UUID jest ignorowane w niektórych kontekstach, ponieważ DB zakłada, że typ nie ma znaczącego uporządkowania. Jeśli okaże się, że jest to przypadek jawnie rzutuj identyfikator UUID na typ łańcucha w klauzuli kolejności lub owiń wokół niego jakąś inną funkcję, jak CHECKSUM()
w SQL Server (może występować niewielka różnica w wydajności, ponieważ kolejność zostanie wykonana na wartości 32-bitowe, a nie 128-bitowe, ale czy korzyść z tego przewyższy koszt uruchomienia CHECKSUM()
według wartości najpierw, zostawię cię do przetestowania).
Dygresja
Jeśli chcesz dowolne, ale nieco powtarzalne porządkowanie, uporządkuj według względnie niekontrolowanego podzbioru danych w samych wierszach. Na przykład jedno lub drugie zwróci nazwy w dowolnej, ale powtarzalnej kolejności:
SELECT display_name FROM tr_person ORDER BY CHECKSUM(display_name), display_name -- order by the checksum of some of the row's data
SELECT display_name FROM tr_person ORDER BY SUBSTRING(display_name, LEN(display_name)/2, 128) -- order by part of the name field, but not in any an obviously recognisable order)
Arbitralne, ale powtarzalne porządki nie są często przydatne w aplikacjach, chociaż mogą być przydatne w testowaniu, jeśli chcesz przetestować jakiś kod na wynikach w różnych zamówieniach, ale chcesz móc powtarzać każde uruchomienie kilka razy w ten sam sposób (aby uzyskać średni czas wyniki z kilku przebiegów lub testowanie, czy poprawka dokonana w kodzie usuwa problem lub nieefektywność poprzednio zaznaczoną przez określony zestaw wyników wejściowych, lub po prostu do testowania, czy kod jest „stabilny”, czyli zwraca ten sam wynik za każdym razem jeśli wysłane te same dane w danej kolejności).
Tej sztuczki można także użyć do uzyskania bardziej dowolnych wyników z funkcji, które nie pozwalają na wywołania niedeterministyczne, takie jak NEWID () w ich ciele. Ponownie, nie jest to coś, co może być często przydatne w prawdziwym świecie, ale może się przydać, jeśli chcesz, aby funkcja zwróciła coś losowego, a „losowe ish” jest wystarczająco dobre (ale pamiętaj, aby pamiętać o regułach, które określają kiedy ewaluowane są funkcje zdefiniowane przez użytkownika, tj. zwykle tylko raz na wiersz lub wyniki mogą nie być zgodne z oczekiwaniami / wymaganiami).
Wydajność
Jak zauważa EBarr, mogą wystąpić problemy z wydajnością w każdym z powyższych. W przypadku więcej niż kilku wierszy masz prawie gwarancję, że dane wyjściowe są buforowane do tempdb, zanim żądana liczba wierszy zostanie odczytana w odpowiedniej kolejności, co oznacza, że nawet jeśli szukasz pierwszej 10, możesz znaleźć pełny indeks skanowanie (lub, co gorsza, skanowanie tabeli) odbywa się wraz z ogromnym blokiem zapisu do tempdb. Dlatego niezwykle ważne może być, podobnie jak w przypadku większości rzeczy, porównywanie realistycznych danych przed użyciem ich w produkcji.