MySQL: select casuale con paginazione

Selezionare una serie di righe da una tabella in modo casuale è semplicissimo, basta usare ORDER BY RAND() nella nostra select. Alcuni preferiscono usare anche tecniche diverse, che vanno dall’uso di PHP alla scrittura di select particolari. Il motivo è che ORDER BY RAND() risulta lenta in quanto MySQL crea una tabella temporanea con tutti i risultati e assegna poi ad ogni riga un indice casuale, ritornando poi un risultato ordinate (casuale)!

Comunque, quello che vorrei mostrare, invece, è come risolvere la paginazione di righe casuali. Come è ovvio eseguendo una select del tipo:

1
SELECT * FROM `table` LIMIT amount OFFSET offset;

Otteniamo una lista – non ordinata, se non per inserimento – di righe che, tramite offset possiamo paginare. Se ordiniamo tutto in modo casuale:

1
SELECT * FROM `table` ORDER BY RAND() LIMIT amount OFFSET offset;

Diventa immediatamente chiaro il problema! La prima volta, quando offset è uguale a 0, verranno estratte un numero pari ad amount di righe in modo casuale. E fino qui nulla di strano. Tuttavia quando offset sarà incrementato del valore di amount essendo l’ordine casuale, sicuramente otterremo righe già estratte precedentemente! La soluzione, apparentemente complessa, è data dalla stessa funzione RAND(). Quest’ultima, infatti, permette di creare una sequenza randomica che si mantiene nel tempo, tramite l’uso del parametro seed. Scrivendo, ad esempio:

1
SELECT * FROM `table` ORDER BY RAND(1234) LIMIT amount OFFSET offset;

Otteremo una sequenza casuale che, se rieseguita, sarà sempre la stessa! Ovviamente siamo ancora a metà dell’opera, perché la domanda che sorge inevitabilmente spontanea è: ok, comunque sia in questo modo l’utente vedrà si gli elementi ordinati in modo casuale (la prima volta) ma sarà sempre lo stesso nel tempo!

La soluzione è semplice: generare un seed in modo tale che sia duraturo ma variabile, ovvero, un seed per sessione ad esempio. Potremmo, quindi, generare un seed in modo casuale, inserirlo nella $_SESSION e utilizzarlo per tutta la durata della navigazione. Oppure, se preferite, una soluzione più sottile:

1
2
$ip = str_replace('.', '', $_SERVER['REMOTE_ADDR']);
$seed = ($ip + date('Hjn') );

In questo modo una utenza, identificata da $_SERVER['REMOTE_ADDR'] paginerà in modo casuale – ma coerente – all’interno di un’ora. Poi, ovviamente, potete modificare a vostro piacere in base all’esigenze.

Non ci sono commenti per questo Post

Lascia un commento

TAG XHTML PERMESSI: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> INSERIMENTO CODICE:
<pre></pre> // blocco generico
					<code></code> // blocco generico
					[cc_actionscript][/cc_actionscript] // Actionscript
					[cc_actionscript3][/cc_actionscript3] // Actionscript 3
					[cc_css][/cc_css] // CSS Style Sheet
					[cc_html][/cc_html] // HTML
					[cc_js][/cc_js] // Javascript
					[cc_objc][/cc_objc] // Objective-C
					[cc_php][/cc_objc] // PHP
					[cc_sql][/cc_sql] // SQL


Stop SOPA