Pradeep Adiga első javaslata, ORDER BY NEWID(), rendben van, és amit a múltban már használtam ebből az okból.

Vigyázzunk az RAND() használatával – sok összefüggésben csak egyszer hajtódik végre utasításonként, így a ORDER BY RAND()-nek nem lesz hatása (mivel minden sorra ugyanazt az eredményt kapjuk a RAND()-ból).

Például:

SELECT display_name, RAND() FROM tr_person

visszaad minden nevet a személy táblánkból és egy “véletlen” számot, ami minden sorra ugyanaz. A szám valóban változik a lekérdezés minden egyes futtatásakor, de minden egyes sorhoz minden alkalommal ugyanaz.

Hogy megmutassam, hogy ugyanez a helyzet a ORDER BY záradékban használt RAND() esetén is, megpróbálom:

SELECT display_name FROM tr_person ORDER BY RAND(), display_name

Az eredmények továbbra is a név szerint vannak rendezve, ami azt jelzi, hogy a korábbi rendezési mezőnek (amelytől a véletlenszerűséget várjuk) nincs hatása, így feltehetően mindig ugyanaz az értéke.

A NEWID() szerinti sorrendezés azonban működik, mert ha a NEWID() nem lenne mindig újraértékelve, akkor az UUID-k célja megszakadna, ha sok új sort szúrnánk be egy statemntbe, amelyek kulcsaként egyedi azonosítók szerepelnek, így:

SELECT display_name FROM tr_person ORDER BY NEWID()

a neveket “véletlenszerűen” rendezi.

Más DBMS

A fentiek igazak az MSSQL-re (2005 és 2008 legalábbis, és ha jól emlékszem 2000 is). Az új UUID-t visszaadó függvénynek minden alkalommal ki kell értékelődnie minden DBMS-ben NEWID() az MSSQL alatt, de érdemes ezt a dokumentációban és/vagy saját tesztekkel ellenőrizni. Más tetszőleges eredményű függvények, mint például a RAND() viselkedése DBMS-enként valószínűbb, hogy változik, ezért ismét ellenőrizd a dokumentációt.

Azt is láttam, hogy az UUID értékek szerinti sorrendezést bizonyos kontextusokban figyelmen kívül hagyják, mivel a DB feltételezi, hogy a típusnak nincs értelmes sorrendje. Ha úgy találja, hogy ez az eset áll fenn, akkor a rendezési záradékban az UUID-t kifejezetten egy karakterlánc-típussá kell alakítani, vagy valamilyen más függvényt kell köré tekerni, mint például az SQL Serverben a CHECKSUM() (ebből is adódhat egy kis teljesítménykülönbség, mivel a rendezés nem 128 bites, hanem 32 bites értékekre történik, bár azt, hogy ennek előnye ellensúlyozza-e a CHECKSUM() értékenkénti futtatásának költségét, hagyom, hogy tesztelje).

Side Note

Ha tetszőleges, de valamennyire megismételhető sorrendezést akarsz, rendezd magukat a sorokban lévő adatok valamilyen viszonylag ellenőrizetlen részhalmaza szerint. Például bármelyik vagy ezek közül bármelyik tetszőleges, de megismételhető sorrendben adja vissza a neveket:

A tetszőleges, de megismételhető sorrend nem gyakran hasznos az alkalmazásokban, de hasznos lehet a tesztelésben, ha valamilyen kódot különböző sorrendű eredményeken akarunk tesztelni, de minden futtatást többször ugyanúgy akarunk megismételni (hogy több futtatás során átlagos időzítési eredményeket kapjunk, vagy hogy teszteljük, hogy a kódon végzett javítás megszünteti-e a korábban egy adott bemeneti eredménykészlet által kiemelt problémát vagy hatástalanságot, vagy csak annak tesztelésére, hogy a kód “stabil”-e, azaz minden alkalommal ugyanazt az eredményt adja-e vissza, ha ugyanazokat az adatokat küldjük egy adott sorrendben).

Ez a trükk arra is használható, hogy tetszőlegesebb eredményeket kapjunk olyan függvényekből, amelyek nem engedik meg a testükön belül a NEWID()-hoz hasonló nemdeterminisztikus hívásokat. Ez megint csak nem olyasmi, ami valószínűleg nem lesz gyakran hasznos a való világban, de jól jöhet, ha azt akarod, hogy egy függvény valami véletlenszerűt adjon vissza, és a “véletlenszerű” elég jó (de vigyázz, hogy ne feledd a szabályokat, amelyek meghatározzák, hogy a felhasználó által definiált függvények mikor értékelődnek ki, azaz általában csak egyszer soronként, különben az eredményed nem lehet az, amit vársz/kívánsz).

Teljesítmény

Amint EBarr rámutat, a fentiek bármelyikével lehetnek teljesítményproblémák. Néhány sornál több sor esetén szinte garantált, hogy a kimenet előbb kerül ki a tempdb-be, mint hogy a kért számú sort a megfelelő sorrendben visszaolvassa, ami azt jelenti, hogy még ha a top 10-et keresed is, előfordulhat, hogy egy teljes index scan (vagy rosszabb esetben table scan) történik egy hatalmas tempdb-be írási blokkal együtt. Ezért életbevágóan fontos lehet, mint a legtöbb dolog esetében, hogy reális adatokkal végezzünk benchmarkot, mielőtt ezt produktívan használnánk.

admin

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.

lg