Risposte:
Un ottimo post che gestisce diversi casi, da semplici, a spazi vuoti, a non uniformi con spazi vuoti.
http://jan.kneschke.de/projects/mysql/order-by-rand/
Per il caso più generale, ecco come lo fai:
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
Ciò suppone che la distribuzione degli ID sia uguale e che possano esserci lacune nell'elenco degli ID. Vedi l'articolo per esempi più avanzati
mysqli_fetch_assoc($result)
? O quei 10 risultati non sono necessariamente distinguibili?
SELECT column FROM table
ORDER BY RAND()
LIMIT 10
Non è la soluzione efficiente ma funziona
ORDER BY RAND()
è relativamente lento
SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10
prende 0,0010, senza LIMIT 10 ci sono voluti 0,0012 (in quella tabella 3500 parole).
Query semplice che ha prestazioni eccellenti e funziona con lacune :
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) as t2 ON t1.id=t2.id
Questa query su una tabella 200K richiede 0,08 secondi e la versione normale (SELEZIONA * DA tbl ORDINA PER RAND () LIMIT 10) richiede 0,35 secondi sulla mia macchina.
Questo è veloce perché la fase di ordinamento utilizza solo la colonna ID indicizzata. Puoi vedere questo comportamento nella spiegazione:
SELEZIONA * DA tbl ORDINA PER RAND () LIMIT 10:
SELEZIONA * DA tbl COME t1 UNISCITI (SELEZIONA ID DA tbl ORDINA PER RAND () LIMIT 10) come t2 ON t1.id = t2.id
Versione ponderata : https://stackoverflow.com/a/41577458/893432
Ricevo query veloci (circa 0,5 secondi) con una CPU lenta , selezionando 10 righe casuali in un registro di MySQL da 400 GB di dimensioni non memorizzate nella cache di 2 GB. Vedi qui il mio codice: selezione rapida di righe casuali in MySQL
<?php
$time= microtime_float();
$sql='SELECT COUNT(*) FROM pages';
$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);
$sql="SELECT id FROM pages WHERE RAND()*$num_records<20
ORDER BY RAND() LIMIT 0,10";
$rquery= BD_Ejecutar($sql);
while(list($id)=mysql_fetch_row($rquery)){
if($id_in) $id_in.=",$id";
else $id_in="$id";
}
mysql_free_result($rquery);
$sql="SELECT id,url FROM pages WHERE id IN($id_in)";
$rquery= BD_Ejecutar($sql);
while(list($id,$url)=mysql_fetch_row($rquery)){
logger("$id, $url",1);
}
mysql_free_result($rquery);
$time= microtime_float()-$time;
logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);
?>
ORDER BY RAND()
FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';
per vederlo.
ORDER BY RAND()
è che ordina solo gli ID (non le righe intere), quindi la tabella temporanea è più piccola, ma deve comunque ordinarle tutte.
È una query molto semplice e a riga singola.
SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
order by rand()
è molto lento se il tavolo è grande
Dal libro:
Scegli una riga casuale usando un offset
Ancora un'altra tecnica che evita i problemi riscontrati nelle alternative precedenti è quella di contare le righe nel set di dati e restituire un numero casuale compreso tra 0 e il conteggio. Quindi utilizzare questo numero come offset quando si esegue una query sul set di dati
<?php
$rand = "SELECT ROUND(RAND() * (SELECT COUNT(*) FROM Bugs))";
$offset = $pdo->query($rand)->fetch(PDO::FETCH_ASSOC);
$sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->execute( $offset );
$rand_bug = $stmt->fetch();
Utilizza questa soluzione quando non puoi assumere valori chiave contigui e devi assicurarti che ogni riga abbia una probabilità pari di essere selezionata.
SELECT count(*)
diventa lento.
Come selezionare righe casuali da una tabella:
Da qui: selezionare le righe casuali in MySQL
Un rapido miglioramento rispetto alla "scansione delle tabelle" consiste nell'utilizzare l'indice per raccogliere ID casuali.
SELECT *
FROM random, (
SELECT id AS sid
FROM random
ORDER BY RAND( )
LIMIT 10
) tmp
WHERE random.id = tmp.sid;
PRIMARY KEY
).
Bene, se non hai spazi vuoti nelle tue chiavi e sono tutti numerici, puoi calcolare numeri casuali e selezionare quelle righe. ma questo probabilmente non sarà il caso.
Quindi una soluzione sarebbe la seguente:
SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1
che sostanzialmente assicurerà di ottenere un numero casuale nell'intervallo dei tasti e quindi selezionare il migliore successivo che è maggiore. devi farlo 10 volte.
tuttavia questo NON è davvero casuale perché molto probabilmente le tue chiavi non saranno distribuite uniformemente.
È davvero un grosso problema e non è facile da risolvere che soddisfa tutti i requisiti, il rand () di MySQL è il migliore che puoi ottenere se vuoi davvero 10 righe casuali.
C'è comunque un'altra soluzione che è veloce ma ha anche un compromesso quando si tratta di casualità, ma potrebbe adattarsi meglio a te. Leggi qui: Come posso ottimizzare la funzione ORDER BY RAND () di MySQL?
La domanda è quanto ti serve che sia casuale.
Puoi spiegarci un po 'di più in modo che io possa darti una buona soluzione.
Ad esempio, un'azienda con cui ho lavorato aveva una soluzione in cui avevano bisogno di casualità assoluta estremamente veloce. Alla fine hanno pre-popolato il database con valori casuali che sono stati selezionati in ordine decrescente e successivamente impostati su valori casuali diversi.
Se non aggiorni quasi mai, potresti anche riempire un ID incrementale in modo da non avere spazi vuoti e puoi semplicemente calcolare i tasti casuali prima di selezionare ... Dipende dal caso d'uso!
Id
e tutte le tue domande casuali ti restituiranno quello Id
.
FLOOR(RAND()*MAX(id))
è distorto verso la restituzione di ID più grandi.
Avevo bisogno di una query per restituire un gran numero di righe casuali da una tabella piuttosto grande. Questo è quello che mi è venuto in mente. Per prima cosa ottieni l'ID record massimo:
SELECT MAX(id) FROM table_name;
Quindi sostituire quel valore in:
SELECT * FROM table_name WHERE id > FLOOR(RAND() * max) LIMIT n;
Dove max è l'ID record massimo nella tabella e n è il numero di righe desiderate nel set di risultati. L'ipotesi è che non ci siano lacune nell'ID record, anche se dubito che ciò influirebbe sul risultato se non ci fosse (non l'ho provato però). Ho anche creato questa procedura memorizzata per essere più generica; passare il nome della tabella e il numero di righe da restituire. Sto eseguendo MySQL 5.5.38 su Windows 2008, 32 GB, doppio 3GHz E5450 e su una tabella con 17.361.264 righe è abbastanza coerente a ~ .03 sec / ~ 11 sec per restituire 1.000.000 di righe. (i tempi sono di MySQL Workbench 6.1; puoi anche usare CEIL invece di FLOOR nella seconda istruzione select a seconda delle tue preferenze)
DELIMITER $$
USE [schema name] $$
DROP PROCEDURE IF EXISTS `random_rows` $$
CREATE PROCEDURE `random_rows`(IN tab_name VARCHAR(64), IN num_rows INT)
BEGIN
SET @t = CONCAT('SET @max=(SELECT MAX(id) FROM ',tab_name,')');
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @t = CONCAT(
'SELECT * FROM ',
tab_name,
' WHERE id>FLOOR(RAND()*@max) LIMIT ',
num_rows);
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$
poi
CALL [schema name].random_rows([table name], n);
Tutte le risposte migliori sono già state pubblicate (principalmente quelle che fanno riferimento al link http://jan.kneschke.de/projects/mysql/order-by-rand/ ).
Voglio individuare un'altra possibilità di accelerazione: la memorizzazione nella cache . Pensa al motivo per cui devi ottenere righe casuali. Probabilmente vuoi visualizzare alcuni post casuali o annunci casuali su un sito web. Se ricevi 100 req / s, è davvero necessario che ogni visitatore ottenga righe casuali? Di solito è del tutto corretto memorizzare nella cache queste X righe casuali per 1 secondo (o anche 10 secondi). Non importa se 100 visitatori unici nello stesso 1 secondo ottengono gli stessi post casuali, perché il secondo successivo altri 100 visitatori riceveranno un set di post diverso.
Quando si utilizza questa memorizzazione nella cache, è possibile utilizzare anche alcune delle soluzioni più lente per ottenere i dati casuali in quanto verranno recuperati da MySQL solo una volta al secondo, indipendentemente dalle richieste.
Ho migliorato la risposta di @Riedsio. Questa è la query più efficiente che riesco a trovare su una tabella di grandi dimensioni, distribuita in modo uniforme con lacune (testata per ottenere 1000 righe casuali da una tabella con> 2.6B righe).
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
Lasciami spacchettare cosa sta succedendo.
@max := (SELECT MAX(id) FROM table)
MAX(id)
ogni volta che è necessaria una rigaSELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
Fare l'unione ti aiuta ad adattare tutto in 1 query in modo da evitare di fare più query. Inoltre, consente di risparmiare il sovraccarico del calcolo MAX(id)
. A seconda dell'applicazione, questo potrebbe importare molto o molto poco.
Si noti che questo ottiene solo gli ID e li ottiene in ordine casuale. Se vuoi fare qualcosa di più avanzato ti consiglio di farlo:
SELECT t.id, t.name -- etc, etc
FROM table t
INNER JOIN (
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
) x ON x.id = t.id
ORDER BY t.id
LIMIT 1
per LIMIT 30
tutto il mondo nella query
LIMIT 1
a LIMIT 30
otterrai 30 record di fila da un punto casuale nella tabella. Dovresti invece avere 30 copie della (SELECT id FROM ....
parte nel mezzo.
Riedsio
rispondi. Ho provato con 500 hit al secondo sulla pagina usando PHP 7.0.22 e MariaDB su centos 7, con Riedsio
risposta ho ottenuto oltre 500 risposte extra di successo quindi la tua risposta.
Ho usato questo http://jan.kneschke.de/projects/mysql/order-by-rand/ pubblicato da Riedsio (ho usato il caso di una procedura memorizzata che restituisce uno o più valori casuali):
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
INSERT INTO rands
SELECT r1.id
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
Nell'articolo risolve il problema delle lacune negli ID che causano risultati non casuali mantenendo una tabella (usando i trigger, ecc ... vedi l'articolo); Sto risolvendo il problema aggiungendo un'altra colonna alla tabella, popolata con numeri contigui, a partire da 1 ( modifica: questa colonna viene aggiunta alla tabella temporanea creata dalla subquery in fase di runtime, non influisce sulla tabella permanente):
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
SET @no_gaps_id := 0;
INSERT INTO rands
SELECT r1.id
FROM (SELECT id, @no_gaps_id := @no_gaps_id + 1 AS no_gaps_id FROM random) AS r1 JOIN
(SELECT (RAND() *
(SELECT COUNT(*)
FROM random)) AS id)
AS r2
WHERE r1.no_gaps_id >= r2.id
ORDER BY r1.no_gaps_id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
Nell'articolo vedo che ha fatto di tutto per ottimizzare il codice; non ho idea se / quanto i miei cambiamenti abbiano un impatto sulle prestazioni ma per me funziona molto bene.
@no_gaps_id
nessun indice può essere usato, quindi se cerchi la EXPLAIN
tua query, hai Using filesort
e Using where
(senza indice) per le subquery, in contrasto con la query originale.
Ecco un punto di svolta che può essere utile per molti;
Ho una tabella con 200k righe, con ID sequenziali , dovevo scegliere N righe casuali, quindi ho scelto di generare valori casuali basati sull'ID più grande nella tabella, ho creato questo script per scoprire qual è l'operazione più veloce:
logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();
I risultati sono:
36.8418693542479
ms0.241041183472
ms0.216960906982
msSulla base di questi risultati, la descrizione dell'ordine è l'operazione più veloce per ottenere l'id massimo,
ecco la mia risposta alla domanda:
SELECT GROUP_CONCAT(n SEPARATOR ',') g FROM (
SELECT FLOOR(RAND() * (
SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 10) a
...
SELECT * FROM tbl WHERE id IN ($result);
Cordiali saluti: Per ottenere 10 righe casuali da una tabella 200k, mi ci sono voluti 1,78 ms (comprese tutte le operazioni sul lato php)
LIMIT
leggermente: puoi ottenere duplicati.
Questo è super veloce ed è casuale al 100% anche se hai delle lacune.
x
di righe disponibiliSELECT COUNT(*) as rows FROM TABLE
a_1,a_2,...,a_10
tra 0 ex
SELECT * FROM TABLE LIMIT 1 offset a_i
per i = 1, ..., 10Ho trovato questo trucco nel libro SQL Antipatterns di Bill Karwin .
SELECT column FROM table ORDER BY RAND() LIMIT 10
è in O (nlog (n)). Quindi sì, questa è la soluzione veloce e funziona per qualsiasi distribuzione di ID.
x
. Direi che questa non è una generazione casuale di 10 righe. Nella mia risposta, è necessario eseguire la query nel passaggio tre 10 volte, ovvero si ottiene solo una riga per esecuzione e non preoccuparsi se l'offset si trova alla fine della tabella.
Combina la risposta di @redsio con una tabella temporanea (600K non è poi così tanto):
DROP TEMPORARY TABLE IF EXISTS tmp_randorder;
CREATE TABLE tmp_randorder (id int(11) not null auto_increment primary key, data_id int(11));
INSERT INTO tmp_randorder (data_id) select id from datatable;
E poi prendi una versione di @redsios Risposta:
SELECT dt.*
FROM
(SELECT (RAND() *
(SELECT MAX(id)
FROM tmp_randorder)) AS id)
AS rnd
INNER JOIN tmp_randorder rndo on rndo.id between rnd.id - 10 and rnd.id + 10
INNER JOIN datatable AS dt on dt.id = rndo.data_id
ORDER BY abs(rndo.id - rnd.id)
LIMIT 1;
Se il tavolo è grande, puoi setacciare nella prima parte:
INSERT INTO tmp_randorder (data_id) select id from datatable where rand() < 0.01;
Versione: è possibile mantenere il tavolo tmp_randorder
persistente , chiamarla datatable_idlist. Ricrea la tabella in determinati intervalli (giorno, ora), poiché anche avrà buchi. Se il tuo tavolo diventa molto grande, puoi anche riempire i buchi
selezionare l.data_id come intero da datatable_idlist l sinistra unire datatable dt su dt.id = l.data_id dove dt.id è nullo;
Versione: assegna al tuo set di dati una colonna random_sortorder direttamente nella tabella dei dati o in una tabella aggiuntiva persistente datatable_sortorder
. Indicizza quella colonna. Genera un valore casuale nella tua applicazione (lo chiamerò $rand
).
select l.*
from datatable l
order by abs(random_sortorder - $rand) desc
limit 1;
Questa soluzione discrimina le 'righe di bordo' con il più alto e il più basso random_sortorder, quindi riorganizzali a intervalli (una volta al giorno).
Un'altra soluzione semplice sarebbe classificare le righe e recuperarne una in modo casuale e con questa soluzione non sarà necessario avere alcuna colonna basata su "ID" nella tabella.
SELECT d.* FROM (
SELECT t.*, @rownum := @rownum + 1 AS rank
FROM mytable AS t,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM mytable))) AS n
) d WHERE rank >= @cnt LIMIT 10;
È possibile modificare il valore limite in base alla necessità di accedere a tutte le righe che si desidera, ma si tratterebbe principalmente di valori consecutivi.
Tuttavia, se non desideri valori casuali consecutivi, puoi prelevare un campione più grande e selezionarlo a caso. qualcosa di simile a ...
SELECT * FROM (
SELECT d.* FROM (
SELECT c.*, @rownum := @rownum + 1 AS rank
FROM buildbrain.`commits` AS c,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM buildbrain.`commits`))) AS rnd
) d
WHERE rank >= @cnt LIMIT 10000
) t ORDER BY RAND() LIMIT 10;
Un modo che trovo abbastanza buono se esiste un ID generato automaticamente è usare l'operatore modulo '%'. Ad esempio, se sono necessari 10.000 record casuali su 70.000, è possibile semplificare dicendo che è necessario 1 su ogni 7 righe. Questo può essere semplificato in questa query:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0;
Se il risultato della divisione delle righe di destinazione per il totale disponibile non è un numero intero, avrai alcune righe extra rispetto a quanto richiesto, quindi dovresti aggiungere una clausola LIMIT per aiutarti a tagliare il set di risultati in questo modo:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0
LIMIT 10000;
Ciò richiede una scansione completa, ma è più veloce di ORDER BY RAND e, a mio avviso, più semplice da comprendere rispetto ad altre opzioni menzionate in questo thread. Inoltre, se il sistema che scrive nel DB crea gruppi di righe in batch, è possibile che non si ottenga un risultato così casuale come previsto.
Se vuoi un record casuale (non importa se ci sono degli spazi tra gli ID):
PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
FLOOR(RAND() * COUNT(*))
FROM `table_name`);
EXECUTE stmt USING @count;
Ho esaminato tutte le risposte e non credo che nessuno menzioni affatto questa possibilità e non sono sicuro del perché.
Se vuoi la massima semplicità e velocità, a un costo minore, allora per me sembra sensato memorizzare un numero casuale su ogni riga nel DB. Basta creare una colonna aggiuntiva random_number
e impostarne il valore predefinito su RAND()
. Crea un indice su questa colonna.
Quindi, quando vuoi recuperare una riga, genera un numero casuale nel tuo codice (PHP, Perl, qualunque cosa) e confrontalo con la colonna.
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
Immagino che, sebbene sia molto pulito per una singola riga, per dieci righe come l'OP ha chiesto che avresti dovuto chiamarlo dieci volte separate (o inventare una modifica intelligente che mi sfugge immediatamente)
Quanto segue dovrebbe essere veloce, imparziale e indipendente dalla colonna ID. Tuttavia, non garantisce che il numero di righe restituite corrisponderà al numero di righe richieste.
SELECT *
FROM t
WHERE RAND() < (SELECT 10 / COUNT(*) FROM t)
Spiegazione: supponendo che si desideri 10 righe su 100, ogni riga ha 1/10 di probabilità di essere SELEZIONATA che potrebbe essere raggiunta WHERE RAND() < 0.1
. Questo approccio non garantisce 10 righe; ma se la query viene eseguita abbastanza volte il numero medio di righe per esecuzione sarà circa 10 e ogni riga nella tabella verrà selezionata in modo uniforme.
PREPARE stm from 'select * from table limit 10 offset ?';
SET @total = (select count(*) from table);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
Puoi anche applicare una clausola where in questo modo
PREPARE stm from 'select * from table where available=true limit 10 offset ?';
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
Testato su 600.000 righe (700 MB) l'esecuzione della query della tabella ha richiesto ~ 0,016
sec unità disco fisso - EDIT -
L'offset potrebbe assumere un valore vicino alla fine della tabella, il che comporterà che l'istruzione select restituisce meno righe (o forse solo 1 riga), per evitare ciò possiamo ricontrollare offset
dopo averlo dichiarato, in questo modo
SET @rows_count = 10;
PREPARE stm from "select * from table where available=true limit ? offset ?";
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
SET @_offset = (SELECT IF(@total-@_offset<@rows_count,@_offset-@rows_count,@_offset));
SET @_offset = (SELECT IF(@_offset<0,0,@_offset));
EXECUTE stm using @rows_count,@_offset;
Uso questa query:
select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10
tempo di query: 0,016 s
Ecco come lo faccio:
select *
from table_with_600k_rows
where rand() < 10/600000
limit 10
Mi piace perché non richiede altre tabelle, è semplice da scrivere ed è molto veloce da eseguire.
Utilizzare la query semplice di seguito per ottenere dati casuali da una tabella.
SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails
GROUP BY usr_fk_id
ORDER BY cnt ASC
LIMIT 10
Immagino che questo sia il miglior modo possibile ..
SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no