Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como selecionar rapidamente 3 registros aleatórios de uma tabela MySQL de 30k com um filtro where por uma única consulta?


Feio, mas rápido e aleatório. Pode ficar muito feio muito rápido, especialmente com o ajuste descrito abaixo, portanto, certifique-se de que realmente deseja dessa maneira.
(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

A primeira linha aparece com mais frequência do que deveria


Se você tiver grandes lacunas entre os IDs em sua tabela, as linhas logo após essas lacunas terão maior chance de serem buscadas por essa consulta. Em alguns casos, eles aparecerão com muito mais frequência do que deveriam. Isso não pode ser resolvido em geral, mas há uma correção para um caso particular comum:quando há uma lacuna entre 0 e o primeiro ID existente em uma tabela.

Em vez da subconsulta (SELECT RAND()*<max_id> AS ID) use algo como (SELECT <min_id> + RAND()*(<max_id> - <min_id>) AS ID)

Remover duplicatas


A consulta, se usada como está, pode retornar linhas duplicadas. É possível evitar isso usando UNION em vez de UNION ALL . Dessa forma, as duplicatas serão mescladas, mas a consulta não garante mais o retorno de exatamente 3 linhas. Você também pode contornar isso, buscando mais linhas do que precisa e limitando o resultado externo assim:
(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3

Ainda não há garantia de que 3 linhas serão buscadas. Isso só torna mais provável.