Moi!
id |nimi |luokka ----------------- 1 |mersu |1 2 |lehmä |3 3 |derbi |2 4 |bemari |1 5 |volvo |1 6 |kissa |3 7 |banaani|4
Yllä on nyt esimerkkitietokantani. Haluan hakea sieltä jonkun sattumanvaraisen auton. Mutta en osaa. Koko tietokannasta randomin hakeminen onnistuu, mutta jos tietyn arvon pitää olla tietty, menee jo yli. Voisiko joku auttaa?
SELECT * FROM `mikalietaulu` WHERE `luokka` = '1' ORDER BY RAND() LIMIT 1
Kts. esim. http://stackoverflow.com/questions/19412/how-to-request-a-random-row-in-sql . Siellä on annettu ratkaisu, joka lienee useimmiten nopeampi kuin syyskimon ratkaisu.
Kyseessä olevassa tapauksessa asialla tehokkuudella lienee ihan sikana merkitystä (not).
Sitä paitsi, tässä tilanteessa ei haeta kaikista riveistä vaan luokalla suodatetuista riveistä, joka aihettaa sen, että on hyvin suuri todennäköisyys että on isoja rakoja kasautunut väleihin, jolloin toiset arvot ovat suuresti todennäköisempiä kuin toiset -> haisee.
Tehostaa toki voi monella tapaa, mutta se että kannattaako, riippuu ihan kannan koo'osta ja muutenkin käyttötarpeesta, mutta mielestäni antamasi linkki on epätoimiva tähän tapaukseen.
Niin, no ajattelin, että kun Zuber antoi esimerkkitietokantansa, niin ehkäpä tuotantotietokanta voi olla paljon isompi.
Kuinka iso tuotantotietokannan tulisi olla?
Testataanpa:
240 rivistä - kysely kesti 0.0019 sek (order by rand() )
240 rivistä - kysely kesti 0.0008 sek (max-tekniikka)
2304 rivistä - kysely kesti 0.0025 sek (order by rand() )
2304 rivistä - kysely kesti 0.0008 sek (max-tekniikka)
13637 rivistä - kysely kesti 0.0487 sek (order by rand() )
13637 rivistä - kysely kesti 0.0010 sek (max-tekniikka)
Palvelin jolla testasin on tuollainen vanha kehityspalvelimeksi alistettu nuhapumppu.
Toki voisi optimoida, mutta jos tuota linkkaamaasi pätkää soveltaa vaikkapa tuohon esimerkkikantaan (7 riviä), niin todennäköisyysjakauma on:
14% mersu
43% bemari
14% volvo
29% ei yhtään mitään
vs. ORDER BY RAND() 1/7 kaikille + aina tulee tulos
No kas,
Hienoinen aivopieru päässyt edelliseen viestiini:
ORDER BY RAND() tod näk on tietysti 1/3 jokaiselle, eikä 1/7.
Ja sitten tuota max-tekniikka voi toki korjata, niin että se palauttaa aina jotain laittamalla (SELECT MAX(...) -osioon saman WHERE-lauseen kuin itse hakuun.
Mutta silti tuo (max-tekniikka) tekee filtteröinnin jälkeen epätaisaista jälkeä enkä suosittelisi käyttämään sitä missään rajatussa haussa, enkä varsinkaan tässä kun rajaus on suuri. Mutta ihan söpö tekniikka muuten, varsin oivaltavasti käytetty indeksejä.
Aihe on jo aika vanha, joten et voi enää vastata siihen.