Pradeep Adiga navrhuje jako první, ORDER BY NEWID(), je v pořádku a v minulosti jsem ho z tohoto důvodu používal.

S použitím RAND() buďte opatrní – v mnoha kontextech se provádí pouze jednou za příkaz, takže ORDER BY RAND() nebude mít žádný efekt (protože z RAND() dostanete pro každý řádek stejný výsledek).

Například:

SELECT display_name, RAND() FROM tr_person

vrátí každé jméno z naší tabulky osob a „náhodné“ číslo, které je pro každý řádek stejné. Číslo se sice při každém spuštění dotazu mění, ale pokaždé je pro každý řádek stejné.

Abych ukázal, že totéž platí i pro RAND() použité v klauzuli ORDER BY, zkusím:

SELECT display_name FROM tr_person ORDER BY RAND(), display_name

Výsledky jsou stále seřazeny podle jména, což naznačuje, že dřívější třídicí pole (to, které má být náhodné) nemá žádný vliv, takže pravděpodobně má vždy stejnou hodnotu.

Řazení podle NEWID() ale funguje, protože kdyby se NEWID() vždy nepřehodnocovalo, porušil by se účel UUID při vkládání mnoha nových řádků do jednoho statemntu s unikátními identifikátory jako jejich klíčem, takže:

SELECT display_name FROM tr_person ORDER BY NEWID()

pořadí jména „náhodně“.

Jiné DBMS

Výše uvedené platí pro MSSQL (minimálně 2005 a 2008, a pokud si dobře pamatuji, tak i 2000). Funkce vracející nové UUID by měla být vyhodnocena pokaždé ve všech DBMS NEWID() je pod MSSQL, ale vyplatí se to ověřit v dokumentaci a/nebo vlastními testy. Chování dalších funkcí s libovolným výsledkem, jako je RAND(), se v různých DBMS pravděpodobněji liší, takže se opět podívejte do dokumentace.

Také jsem viděl, že řazení podle hodnot UUID je v některých kontextech ignorováno, protože DB předpokládá, že typ nemá smysluplné řazení. Pokud zjistíte, že je to tento případ, explicitně v klauzuli o řazení převeďte UUID na řetězcový typ nebo jej obalte nějakou jinou funkcí, jako je CHECKSUM() v SQL Serveru (i z toho může plynout malý výkonnostní rozdíl, protože řazení se bude provádět na 32bitových hodnotách, nikoli 128bitových, i když to, zda přínos tohoto převáží nad náklady na spuštění CHECKSUM() na hodnotu jako první, nechám na vás, abyste otestovali).

Poznámka na okraj

Pokud chcete libovolné, ale do jisté míry opakovatelné řazení, uspořádejte podle nějaké relativně nekontrolované podmnožiny dat v samotných řádcích. Například některý z nich vrátí jména v libovolném, ale opakovatelném pořadí:

Libovolné, ale opakovatelné uspořádání není v aplikacích často užitečné, může však být užitečné při testování, pokud chcete testovat nějaký kód na výsledcích v různých pořadích, ale chcete mít možnost opakovat každý běh několikrát stejným způsobem (pro získání průměrných výsledků časování v několika bězích nebo pro testování, zda oprava, kterou jste provedli v kódu, odstraňuje problém nebo neefektivitu, na kterou dříve upozornila určitá vstupní sada výsledků, nebo jen pro testování, zda je váš kód „stabilní“ v tom smyslu, že vrací pokaždé stejný výsledek, pokud jsou mu zaslána stejná data v daném pořadí).

Tento trik lze také použít k získání libovolnějších výsledků z funkcí, které ve svém těle neumožňují nedeterministická volání jako NEWID(). Opět to není něco, co by bylo v reálném světě často užitečné, ale mohlo by se to hodit, pokud chcete, aby funkce vracela něco náhodného, a „náhodné“ je dost dobré (ale pozor na pravidla, která určují, kdy se uživatelsky definované funkce vyhodnocují, tj. obvykle jen jednou na řádek, jinak vaše výsledky nemusí být takové, jaké očekáváte/požadujete).

Výkon

Jak upozorňuje EBarr, s každým z výše uvedených postupů mohou být problémy s výkonem. U více než několika řádků je téměř zaručeno, že výstup bude vypsán do tempdb dříve, než bude požadovaný počet řádků načten zpět ve správném pořadí, což znamená, že i když hledáte prvních 10, může se stát, že dojde k úplnému prohledání indexu (nebo hůře, prohledání tabulky) spolu s obrovským blokem zápisu do tempdb. Proto může být životně důležité, stejně jako u většiny věcí, před použitím v produkci provést benchmark s reálnými daty.

admin

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.

lg