Respostas:
Um ótimo post para lidar com vários casos, de simples a lacunas, a não uniformes com lacunas.
http://jan.kneschke.de/projects/mysql/order-by-rand/
Para o caso mais geral, eis como você faz isso:
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
Isso supõe que a distribuição dos IDs seja igual e que possa haver falhas na lista de IDs. Veja o artigo para exemplos mais avançados
mysqli_fetch_assoc($result)
? Ou esses 10 resultados não são necessariamente distinguíveis?
SELECT column FROM table
ORDER BY RAND()
LIMIT 10
Não é a solução eficiente, mas funciona
ORDER BY RAND()
é relativamente lento
SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10
leva 0,0010, sem LIMIT 10 levou 0,0012 (nessa tabela 3500 palavras).
Consulta simples que possui excelente desempenho e funciona com lacunas :
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) as t2 ON t1.id=t2.id
Essa consulta em uma tabela de 200K demora 0,08s e a versão normal (SELECT * FROM t ORDEM POR RAND () LIMITE 10) leva 0,35s na minha máquina.
Isso é rápido porque a fase de classificação usa apenas a coluna de ID indexado. Você pode ver esse comportamento na explicação:
SELECT * FROM t ORDEM POR RAND () LIMITE 10:
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND () LIMITE 10) como t2 ON t1.id = t2.id
Versão ponderada : https://stackoverflow.com/a/41577458/893432
Estou recebendo consultas rápidas (em torno de 0,5 segundos) com uma CPU lenta , selecionando 10 linhas aleatórias em um tamanho de 2 GB sem cache de 2 GB de banco de dados MySQL de registros de 400 K. Veja aqui meu código: Seleção rápida de linhas aleatórias no 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%';
para ver.
ORDER BY RAND()
é simples: ele classifica apenas os IDs (não linhas completas), portanto, a tabela temporária é menor, mas ainda precisa classificar todos eles.
É uma consulta de linha muito simples e única.
SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
order by rand()
é muito lenta se a tabela é grande
Do livro:
Escolha uma linha aleatória usando um deslocamento
Outra técnica que evita problemas encontrados nas alternativas anteriores é contar as linhas no conjunto de dados e retornar um número aleatório entre 0 e a contagem. Em seguida, use esse número como um deslocamento ao consultar o conjunto de dados
<?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();
Use esta solução quando não puder assumir valores de chave contíguos e precisar garantir que cada linha tenha uma chance uniforme de ser selecionada.
SELECT count(*)
fica lento.
Como selecionar linhas aleatórias de uma tabela:
A partir daqui: Selecione linhas aleatórias no MySQL
Uma rápida melhoria em relação à "verificação de tabela" é usar o índice para selecionar IDs aleatórios.
SELECT *
FROM random, (
SELECT id AS sid
FROM random
ORDER BY RAND( )
LIMIT 10
) tmp
WHERE random.id = tmp.sid;
PRIMARY KEY
).
Bem, se você não possui lacunas em suas chaves e todas elas são numéricas, é possível calcular números aleatórios e selecionar essas linhas. mas isso provavelmente não será o caso.
Portanto, uma solução seria a seguinte:
SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1
o que basicamente garantirá que você obtenha um número aleatório no intervalo de suas teclas e selecione o próximo melhor que for maior. você tem que fazer isso 10 vezes.
no entanto, isso NÃO é realmente aleatório, porque suas chaves provavelmente não serão distribuídas uniformemente.
É realmente um grande problema e não é fácil de resolver cumprindo todos os requisitos, o rand () do MySQL é o melhor que você pode obter se você realmente deseja 10 linhas aleatórias.
No entanto, existe outra solução que é rápida, mas também tem uma troca quando se trata de aleatoriedade, mas pode ser mais adequada para você. Leia sobre isso aqui: Como otimizar a função ORDER BY RAND () do MySQL?
A questão é o quão aleatório você precisa.
Você pode explicar um pouco mais para que eu possa lhe dar uma boa solução.
Por exemplo, uma empresa com quem trabalhei tinha uma solução em que precisava de aleatoriedade absoluta extremamente rápida. Eles acabaram preenchendo previamente o banco de dados com valores aleatórios que foram selecionados descendentes e configurados para diferentes valores aleatórios posteriormente novamente.
Se você quase nunca atualizar, também poderá preencher um ID incremental para não ter lacunas e apenas calcular chaves aleatórias antes de selecionar ... Depende do caso de uso!
Id
e todas as suas consultas aleatórias retornarão essa Id
.
FLOOR(RAND()*MAX(id))
está inclinado a retornar IDs maiores.
Eu precisava de uma consulta para retornar um grande número de linhas aleatórias de uma tabela bastante grande. Isto é o que eu vim com. Primeiro, obtenha o ID máximo de registro:
SELECT MAX(id) FROM table_name;
Em seguida, substitua esse valor em:
SELECT * FROM table_name WHERE id > FLOOR(RAND() * max) LIMIT n;
Onde max é o ID máximo de registro na tabela en é o número de linhas que você deseja no seu conjunto de resultados. A suposição é que não há lacunas nos IDs de registro, embora eu duvide que isso afetaria o resultado se houvesse (ainda não tentei). Eu também criei esse procedimento armazenado para ser mais genérico; passe o nome da tabela e o número de linhas a serem retornadas. Estou executando o MySQL 5.5.38 no Windows 2008, 32GB, E5450 duplo de 3GHz, e em uma tabela com 17.361.264 linhas, é bastante consistente em ~ 0,03 s / ~ 11 s para retornar 1.000.000 de linhas. (os horários são do MySQL Workbench 6.1; você também pode usar CEIL em vez de FLOOR na segunda instrução de seleção, dependendo da sua preferência)
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
$$
então
CALL [schema name].random_rows([table name], n);
Todas as melhores respostas já foram publicadas (principalmente as que referenciam o link http://jan.kneschke.de/projects/mysql/order-by-rand/ ).
Quero apontar outra possibilidade de aceleração - cache . Pense por que você precisa obter linhas aleatórias. Provavelmente, você deseja exibir alguma postagem ou anúncio aleatório em um site. Se você está recebendo 100 solicitações / s, é realmente necessário que cada visitante obtenha linhas aleatórias? Normalmente, é perfeitamente bom armazenar em cache essas X linhas aleatórias por 1 segundo (ou até 10 segundos). Não importa se 100 visitantes únicos no mesmo 1 segundo recebem as mesmas postagens aleatórias, porque no segundo seguinte outros 100 visitantes receberão um conjunto diferente de postagens.
Ao usar esse cache, você também pode usar algumas das soluções mais lentas para obter os dados aleatórios, pois eles serão buscados no MySQL apenas uma vez por segundo, independentemente de seus requisitos / s.
Melhorei a resposta que @Riedsio tinha. Esta é a consulta mais eficiente que posso encontrar em uma tabela grande e uniformemente distribuída com lacunas (testada ao obter 1000 linhas aleatórias de uma tabela que possui> 2,6B linhas).
(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)
Deixe-me descompactar o que está acontecendo.
@max := (SELECT MAX(id) FROM table)
MAX(id)
cada vez que você precisa de uma linhaSELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
Fazer a união ajuda a ajustar tudo em uma consulta para evitar que você faça várias consultas. Também permite salvar a sobrecarga do cálculo MAX(id)
. Dependendo do seu aplicativo, isso pode importar muito ou muito pouco.
Observe que isso obtém apenas os IDs e os obtém em ordem aleatória. Se você quiser fazer algo mais avançado, recomendo que você faça o seguinte:
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
para LIMIT 30
todos os lugares em consulta
LIMIT 1
para LIMIT 30
você obteria 30 registros seguidos de um ponto aleatório na tabela. Em vez disso, você deve ter 30 cópias da (SELECT id FROM ....
peça no meio.
Riedsio
responder. Eu tentei com 500 por segundo acessos à página usando PHP 7.0.22 e MariaDB no centos 7, com a Riedsio
resposta eu recebi mais de 500 respostas extra bem-sucedidas que a sua resposta.
Eu usei este http://jan.kneschke.de/projects/mysql/order-by-rand/ publicado por Riedsio (usei o caso de um procedimento armazenado que retorna um ou mais valores aleatórios):
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;
No artigo, ele resolve o problema de lacunas nos IDs, causando resultados não tão aleatórios mantendo uma tabela (usando gatilhos, etc ... consulte o artigo); Estou resolvendo o problema adicionando outra coluna à tabela, preenchida com números contíguos, iniciando em 1 ( editar: esta coluna é adicionada à tabela temporária criada pela subconsulta em tempo de execução, não afeta sua tabela 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;
No artigo, posso ver que ele fez um grande esforço para otimizar o código; não tenho idéia se / quanto minhas alterações afetam o desempenho, mas funcionam muito bem para mim.
@no_gaps_id
índice no pode ser usado, portanto, se você procurar EXPLAIN
sua consulta, você tem Using filesort
e Using where
(sem índice) as subconsultas, em contraste com a consulta original.
Aqui está uma mudança de jogo que pode ser útil para muitos;
Eu tenho uma tabela com 200k linhas, com IDs seqüenciais , eu precisava escolher N linhas aleatórias, então optei por gerar valores aleatórios com base no maior ID da tabela, criei esse script para descobrir qual é a operação mais rápida:
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();
Os resultados são:
36.8418693542479
ms0.241041183472
ms0.216960906982
msCom base nesses resultados, o pedido desc é a operação mais rápida para obter o ID máximo.
Aqui está minha resposta para a pergunta:
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);
FYI: Para obter 10 linhas aleatórias de uma tabela de 200k, levei 1,78 ms (incluindo todas as operações no lado do php)
LIMIT
ligeiramente - você pode obter duplicatas.
Isso é super rápido e é 100% aleatório, mesmo se você tiver lacunas.
x
de linhas que você tem disponívelSELECT COUNT(*) as rows FROM TABLE
a_1,a_2,...,a_10
entre 0 ex
SELECT * FROM TABLE LIMIT 1 offset a_i
para i = 1, ..., 10Encontrei esse truque no livro Antipatterns SQL de Bill Karwin .
SELECT column FROM table ORDER BY RAND() LIMIT 10
está em O (nlog (n)). Então, sim, esta é a solução em jejum e funciona para qualquer distribuição de IDs.
x
. Eu diria que essa não é uma geração aleatória de 10 linhas. Na minha resposta, você deve executar a consulta na etapa três 10 vezes, ou seja, apenas uma linha é executada por execução e não precisa se preocupar se o deslocamento estiver no final da tabela.
Combine a resposta de @redsio com uma tabela temporária (600K não é muito):
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 então pegue uma versão do @redsios Answer:
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 a mesa for grande, você pode peneirar na primeira parte:
INSERT INTO tmp_randorder (data_id) select id from datatable where rand() < 0.01;
Versão: você pode manter a tabela tmp_randorder
persistente, chame-a de datatable_idlist. Recrie essa tabela em determinados intervalos (dia, hora), pois ela também terá furos. Se sua mesa ficar muito grande, você também pode repor buracos
selecione l.data_id como um todo em datatable_idlist l junte à esquerda a tabela de dados dt em dt.id = l.data_id em que dt.id é nulo;
Versão: forneça ao conjunto de dados uma coluna random_sortorder diretamente na tabela de dados ou em uma tabela extra persistente datatable_sortorder
. Indexe essa coluna. Gere um valor aleatório em seu aplicativo (eu vou chamá-lo $rand
).
select l.*
from datatable l
order by abs(random_sortorder - $rand) desc
limit 1;
Esta solução discrimina as 'linhas de borda' com a ordem aleatória mais alta e mais baixa, portanto, reorganize-as em intervalos (uma vez por dia).
Outra solução simples seria classificar as linhas e buscar uma delas aleatoriamente e, com essa solução, você não precisará ter nenhuma coluna baseada em 'ID' na tabela.
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;
Você pode alterar o valor limite conforme sua necessidade de acessar quantas linhas desejar, mas isso geralmente seria valores consecutivos.
No entanto, se você não quiser valores aleatórios consecutivos, poderá buscar uma amostra maior e selecionar aleatoriamente nela. algo como ...
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;
Uma maneira que eu acho muito boa se houver um ID gerado automaticamente é usar o operador de módulo '%'. Por exemplo, se você precisar de 10.000 registros aleatórios em 70.000, poderá simplificar isso dizendo que precisa de 1 em cada 7 linhas. Isso pode ser simplificado nesta consulta:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0;
Se o resultado da divisão das linhas de destino pelo total disponível não for um número inteiro, você terá algumas linhas extras além das solicitadas, portanto, adicione uma cláusula LIMIT para ajudá-lo a aparar o conjunto de resultados da seguinte forma:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0
LIMIT 10000;
Isso requer uma verificação completa, mas é mais rápido que ORDER BY RAND e, na minha opinião, é mais simples de entender do que outras opções mencionadas neste tópico. Além disso, se o sistema que grava no banco de dados cria conjuntos de linhas em lotes, você pode não obter um resultado aleatório como o esperado.
Se você deseja um registro aleatório (não importa se existem lacunas entre os IDs):
PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
FLOOR(RAND() * COUNT(*))
FROM `table_name`);
EXECUTE stmt USING @count;
Examinei todas as respostas e acho que ninguém menciona essa possibilidade, e não sei por que.
Se você deseja maior simplicidade e velocidade, a um custo menor, para mim parece fazer sentido armazenar um número aleatório em cada linha do banco de dados. Basta criar uma coluna extra random_number
, e defina como padrão RAND()
. Crie um índice nesta coluna.
Então, quando você quiser recuperar uma linha, gere um número aleatório no seu código (PHP, Perl, qualquer que seja) e compare-o com a coluna.
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
Eu acho que, embora seja muito legal para uma única linha, dez linhas como o OP pediram que você tivesse que chamá-lo dez vezes separadas (ou criar um ajuste inteligente que me escapa imediatamente)
O seguinte deve ser rápido, imparcial e independente da coluna id. No entanto, não garante que o número de linhas retornadas corresponda ao número de linhas solicitadas.
SELECT *
FROM t
WHERE RAND() < (SELECT 10 / COUNT(*) FROM t)
Explicação: supondo que você queira 10 linhas de 100, cada linha tem 1/10 de probabilidade de ser SELECTada, o que poderia ser alcançado WHERE RAND() < 0.1
. Essa abordagem não garante 10 linhas; mas se a consulta for executada o suficiente, o número médio de linhas por execução será de cerca de 10 e cada linha da tabela será selecionada uniformemente.
PREPARE stm from 'select * from table limit 10 offset ?';
SET @total = (select count(*) from table);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
Você também pode aplicar uma cláusula where assim
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;
Testado em 600.000 linhas (700MB), a execução da consulta da tabela levou ~ 0,016s da unidade HDD
--EDIT--
O deslocamento pode levar um valor próximo ao final da tabela, o que resultará na instrução select retornando menos linhas (ou talvez apenas 1). linha), para evitar isso, podemos verificar offset
novamente depois de declará-lo, assim
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;
Eu uso esta consulta:
select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10
tempo de consulta: 0.016s
É assim que eu faço:
select *
from table_with_600k_rows
where rand() < 10/600000
limit 10
Gosto porque não requer outras tabelas, é simples de escrever e é muito rápido de executar.
Use a consulta simples abaixo para obter dados aleatórios de uma tabela.
SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails
GROUP BY usr_fk_id
ORDER BY cnt ASC
LIMIT 10
Eu acho que essa é a melhor maneira possível ..
SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no