Pergunta

O que é uma maneira rápida de selecionar uma linha aleatória de uma tabela mysql grande?

Eu estou trabalhando em php, mas eu estou interessado em qualquer solução, mesmo que seja em outro idioma.

Foi útil?

Solução

Grab tudo do id, escolher um aleatório a partir dele, e recuperar a linha completa.

Se você sabe do id são sequenciais, sem buracos, você pode simplesmente pegar o máximo e calcular um id aleatório.

Se há buracos aqui e ali, mas principalmente seqüenciais valores, e você não se preocupam com a aleatoriedade ligeiramente inclinada, pegue o valor máximo, calcular um id, e selecione a primeira linha com um id igual ou superior a um você calculou. A razão para a inclinação é seguir esses buracos que de id terá uma maior chance de ser escolhido do que os que seguem outro id.

Se você pedir por acaso, você vai ter uma terrível mesa-scan em suas mãos, ea palavra rápida não se aplica a uma solução deste tipo.

Não faça isso, nem você deve pedir por um GUID, ele tem o mesmo problema.

Outras dicas

Eu sabia que tinha que haver uma maneira de fazê-lo em uma única consulta de uma forma rápida. E aqui está:

Uma maneira rápida, sem envolvimento de código externo, parabéns a

http://jan.kneschke.de/projects/mysql/order -de-rand /

SELECT name
  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;

MediaWiki usa um truque interessante (para especial da Wikipedia: recurso Random): a tabela com os artigos tem uma coluna extra com um número aleatório (gerado quando o artigo é criado). Para obter um artigo aleatório, gerar um número aleatório e obter o artigo com a próxima maior ou menor (não me lembro qual) valor na coluna de números aleatórios. Com um índice, isso pode ser muito rápido. (E MediaWiki é escrito em PHP e desenvolvido para MySQL.)

Esta abordagem pode causar um problema se os números resultantes são mal distribuída; IIRC, isso foi corrigido em MediaWiki, por isso, se você decidir fazê-lo desta forma, você deve dar uma olhada no código para ver como é feito atualmente (provavelmente eles periodicamente regenerar a coluna de número aleatório).

Aqui está uma solução que é executado rapidamente, e torna-se uma melhor distribuição aleatória, sem depender de valores id sendo contígua ou a partir de 1.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

Talvez você poderia fazer algo como:

SELECT * FROM table 
  WHERE id=
    (FLOOR(RAND() * 
           (SELECT COUNT(*) FROM table)
          )
    );

Esta é assumindo os seus números de identificação são todos sequencial sem lacunas.

Adicione uma coluna que contém um valor aleatório calculado para cada linha, e usar isso na cláusula de ordenação, limitando a um resultado sobre a seleção. Isso funciona mais rápido do que ter a mesa de digitalização que causa ORDER BY RANDOM().

Update:. Você ainda precisa calcular algum valor aleatório antes de emitir a declaração SELECT sobre a recuperação, é claro, por exemplo

SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1

Um fácil, mas lento caminho seria (bom para tabelas smallish)

SELECT * from TABLE order by RAND() LIMIT 1

No código pseudo:

sql "select id from table"
store result in list
n = random(size of list)
sql "select * from table where id=" + list[n]

Isso pressupõe que id é uma chave única (primário).

Há uma outra maneira de produzir linhas aleatórias usando apenas uma consulta e sem ordem por rand (). Envolve as variáveis ??definidas pelo usuário. Consulte como produzir linhas aleatórias de uma tabela

A fim de encontrar linhas aleatórias de uma tabela, não use ORDER BY RAND (), porque obriga MySQL para fazer um arquivo completo de classificação e só então recuperar o número linhas limite necessário. Para evitar esse tipo de arquivo completo, use a função RAND () apenas na cláusula where. Ele vai parar assim que alcança o número necessário de linhas. Vejo http://www.rndblog.com/how-to- select-random-linhas-em-mysql /

Se você fizer linha não de exclusão nesta tabela, a forma mais eficiente é:

(se você sabe o id mininum apenas ignorá-lo)

SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1

$randId=mt_rand((int)$row['minId'], (int)$row['maxId']);

SELECT id,name,... FROM table WHERE id=$randId LIMIT 1

Para selecionar várias linhas aleatórias de uma determinada tabela (digamos 'palavras'), nossa equipe veio com essa beleza:

SELECT * FROM
`words` AS r1 JOIN 
(SELECT  MAX(`WordID`) as wid_c FROM `words`) as tmp1
WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n

O clássico "id SELECT FROM tabela ORDER BY RAND () LIMIT 1" é realmente OK.

Veja o trecho acompanhamento do manual do MySQL:

Se você usar LIMIT row_count com ORDER BY, MySQL termina a ordenação logo que ele encontrar os primeiros row_count linhas do resultado ordenada, em vez de ordenar o resultado inteiro.

Com um yo ordem vai fazer uma tabela de verificação completa. Sua melhor se você fizer um select count (*) e, posteriormente, obter uma linha aleatória = rownum entre 0 e o último registro

Dê uma olhada este link por Jan Kneschke ou esta resposta modo ambos discutir a mesma questão. A resposta SO vai sobre várias opções e também tem algumas sugestões boas, dependendo de suas necessidades. Jan vai sobre todas as várias opções e as características de cada performance. Ele acaba com o seguinte para o método mais otimizado pelo qual fazer isso dentro de um MySQL selecione:

SELECT name
  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;

HTH,

-Dipin

Eu sou um pouco novo para SQL, mas como sobre a geração de um número aleatório em PHP e usando

SELECT * FROM the_table WHERE primary_key >= $randNr

isto não resolve o problema com furos na tabela.

Mas aqui está uma torção no lassevks sugestão:

SELECT primary_key FROM the_table

Use mysql_num_rows () em PHP criar um número aleatório com base no resultado acima:

SELECT * FROM the_table WHERE primary_key = rand_number

Em uma nota lateral quão lenta é SELECT * FROM the_table:
Criando um número aleatório baseado em mysql_num_rows() e, em seguida, mover o ponteiro de dados para que mysql_data_seek() ponto. Quão lento este vai ser em grandes mesas com dizer um milhão de linhas?

Eu corri para o problema onde meus IDs não foram seqüencial. O que eu vim com isso.

SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1

As linhas retornadas são aproximadamente 5, mas limitá-lo a 1.

Se você quiser adicionar outra cláusula em que se torna um pouco mais interessante. Digamos que você deseja procurar produtos em desconto.

SELECT * FROM products WHERE RAND()<=(100/(SELECT COUNT(*) FROM pt_products)) AND discount<.2 LIMIT 1

O que você tem a fazer é se certificar de que estão voltando resultado suficiente que é por isso que eu tê-lo definido como 100. Ter um ONDE desconto <0,2 cláusula na subconsulta era 10x mais lento, por isso é melhor para retornar mais resultados e limite .

Eu vejo aqui um monte de solução. Um ou dois parece ok, mas outras soluções têm algumas restrições. Mas a seguinte solução irá trabalhar para todos situação

select a.* from random_data a, (select max(id)*rand() randid  from random_data) b
     where a.id >= b.randid limit 1;

Aqui, id, não precisam ser sequenciais. Poderia ser qualquer coluna de chave primária / exclusiva / auto incremento. Consulte o seguinte maneira mais rápida de selecionar uma linha aleatória de uma tabela MySQL grande

Graças Zillur - www.techinfobest.com

Use o abaixo consulta para obter a linha aleatória

SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails 
GROUP BY usr_fk_id 
ORDER BY cnt ASC  
LIMIT 1

No meu caso a minha mesa tem um id como chave primária, auto-incremento sem intervalos, para que eu possa usar COUNT(*) ou MAX(id) para obter o número de linhas.

Eu fiz este script para testar 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:

  • Conde: 36.8418693542479 ms
  • Max: 0.241041183472 ms
  • Ordem : 0.216960906982 ms

Resposta com o método ordem:

SELECT FLOOR(RAND() * (
    SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 1

...
SELECT * FROM tbl WHERE id = $result;

Eu tenho usado essa e o trabalho foi feito a referência href="https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/" aqui

SELECT * FROM myTable WHERE RAND()<(SELECT ((30/COUNT(*))*10) FROM myTable) ORDER BY RAND() LIMIT 30;

Criar uma função para fazer isso provavelmente a melhor resposta e resposta mais rápida aqui!

A Favor -. Funciona mesmo com lacunas e extremamente rápidos

<?

$sqlConnect = mysqli_connect('localhost','username','password','database');

function rando($data,$find,$max = '0'){
   global $sqlConnect; // Set as mysqli connection variable, fetches variable outside of function set as GLOBAL
   if($data == 's1'){
     $query = mysqli_query($sqlConnect, "SELECT * FROM `yourtable` ORDER BY `id` DESC LIMIT {$find},1");

     $fetched_data = mysqli_fetch_assoc($query);
      if(mysqli_num_rows($fetched_data>0){
       return $fetch_$data;
      }else{
       rando('','',$max); // Start Over the results returned nothing
      }
   }else{
     if($max != '0'){
        $irand = rand(0,$max); 
        rando('s1',$irand,$max); // Start rando with new random ID to fetch
     }else{

        $query = mysqli_query($sqlConnect, "SELECT `id` FROM `yourtable` ORDER BY `id` DESC LIMIT 0,1");
        $fetched_data = mysqli_fetch_assoc($query);
        $max = $fetched_data['id'];
        $irand = rand(1,$max);
        rando('s1',$irand,$max); // Runs rando against the random ID we have selected if data exist will return
     }
   }
 }

 $your_data = rando(); // Returns listing data for a random entry as a ASSOC ARRAY
?>

Tenha em mente este código como não foi testado, mas é um conceito de trabalho para retornar entradas aleatórias mesmo com lacunas .. Enquanto as lacunas não são grandes o suficiente para causar um problema de tempo de carregamento.

método rápido e sujo:

SET @COUNTER=SELECT COUNT(*) FROM your_table;

SELECT PrimaryKey
FROM your_table
LIMIT 1 OFFSET (RAND() * @COUNTER);

A complexidade da primeira consulta é O (1) para tabelas MyISAM.

A segunda consulta acompanha uma varredura completa da tabela. Complexidade = O (n)

sujo e método rápido:

Mantenha uma tabela separada por apenas esta finalidade. Você também deve inserir as mesmas linhas para esta tabela, sempre inserindo para a tabela original. Assunção:. Não DELETEs

CREATE TABLE Aux(
  MyPK INT AUTO_INCREMENT,
  PrimaryKey INT
);

SET @MaxPK = (SELECT MAX(MyPK) FROM Aux);
SET @RandPK = CAST(RANDOM() * @MaxPK, INT)
SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK = @RandPK);

Se DELETEs são permitidos,

SET @delta = CAST(@RandPK/10, INT);

SET @PrimaryKey = (SELECT PrimaryKey
                   FROM Aux
                   WHERE MyPK BETWEEN @RandPK - @delta AND @RandPK + @delta
                   LIMIT 1);

A complexidade global é O (1).

SELECT DISTINCT * FROM yourTable WHERE 4 = 4 LIMIT 1;

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top