Então, eu encontrei vários exemplos para encontrar um registro aleatório no Rails 2 - o método preferido parece ser:
Thing.find :first, :offset => rand(Thing.count)
Sendo um novato, não tenho certeza de como isso pode ser construído usando a nova sintaxe de localização no Rails 3.
Então, qual é o "Rails 3 Way" para encontrar um registro aleatório?
Respostas:
ou
Na verdade, no Rails 3 todos os exemplos funcionarão. Mas o uso da ordem
RANDOM
é bastante lento para grandes tabelas, mas com mais estilo sqlUPD. Você pode usar o seguinte truque em uma coluna indexada (sintaxe do PostgreSQL):
fonte
RAND()
ouRANDOM()
. GraçasEstou trabalhando em um projeto ( Rails 3.0.15, ruby 1.9.3-p125-perf ) em que o banco de dados está no host local e a tabela de usuários possui um pouco mais de 100 mil registros .
Usando
é bem lento
torna-se
e leva de 8 a 12 segundos para responder !!
Log do Rails:
da explicação do mysql
Você pode ver que nenhum índice é usado ( Chaves_Possíveis = NULL ), uma tabela temporária é criada e uma passagem extra é necessária para buscar o valor desejado ( extra = Usando temporário; Usando filesort ).
Por outro lado, dividindo a consulta em duas partes e usando Ruby, temos uma melhoria razoável no tempo de resposta.
(; nada para uso do console)
Log do Rails:
e a explicação do mysql prova o porquê:
agora podemos usar apenas índices e a chave primária e executar o trabalho cerca de 500 vezes mais rápido!
ATUALIZAR:
como apontado por icantbecool nos comentários, a solução acima apresenta uma falha se houver registros excluídos na tabela.
Uma solução alternativa para isso pode ser
que se traduz em duas consultas
e roda em cerca de 500ms.
fonte
RAND(id)
você não terá uma ordem aleatória diferente a cada consulta. UseRAND()
se desejar uma ordem diferente para cada consulta.Se estiver usando o Postgres
Se estiver usando MySQL
Nos dois casos, você seleciona 5 registros aleatoriamente na tabela Usuários. Aqui está a consulta SQL real exibida no console.
fonte
Fiz uma pedra preciosa rails 3 para fazer isso com melhor desempenho em tabelas grandes e permitir que você encadeie relações e escopos:
https://github.com/spilliton/randumb
(editar): O comportamento padrão da minha jóia basicamente usa a mesma abordagem acima agora, mas você tem a opção de usar da maneira antiga, se quiser :)
fonte
Muitas das respostas postadas na verdade não apresentam bom desempenho em tabelas bastante grandes (mais de 1 milhão de linhas). A ordenação aleatória demora rapidamente alguns segundos e a contagem na mesa também leva bastante tempo.
Uma solução que funciona bem para mim nessa situação é usar
RANDOM()
com uma condição where:Em uma tabela com mais de um milhão de linhas, essa consulta geralmente leva menos de 2ms.
fonte
take
função que forneceLIMIT(1)
consulta, mas retorna um único elemento em vez de matriz. Portanto, não precisamos invocar #first
aqui vamos nós
trilhos maneira
uso
ou o segundo pensamento é
uso:
fonte
Couldn't find all Users with 'id': (first, {:offset=>1}) (found 0 results, but was looking for 2)
"RANDOM()"
em vez disso ...Isso foi muito útil para mim, no entanto, eu precisava de um pouco mais de flexibilidade, então foi isso que fiz:
Case1: Localizando uma fonte de registro aleatório : trevor turk site
Adicione isso ao modelo Thing.rb
então no seu controlador você pode chamar algo assim
Case2: Encontrar vários registros aleatórios (sem repetições) fonte: não consigo lembrar
Eu precisava encontrar 10 registros aleatórios sem repetições, então foi o que eu achei que funcionou
No seu controlador:
Isso encontrará 10 registros aleatórios, no entanto, vale ressaltar que, se o banco de dados for particularmente grande (milhões de registros), isso não seria o ideal e o desempenho será prejudicado. É vai executar bem até alguns milhares de registros, o que foi suficiente para mim.
fonte
O método Ruby para escolher aleatoriamente um item de uma lista é
sample
. Querendo criar um eficientesample
para o ActiveRecord, e com base nas respostas anteriores, usei:Eu coloquei isso
lib/ext/sample.rb
e carreguei com isso emconfig/initializers/monkey_patches.rb
:fonte
#count
fará uma chamada para o banco de dados para aCOUNT
. Se o registro já estiver carregado, isso pode ser uma má ideia. Um refator seria o uso,#size
pois ele decidirá se#count
deve ser usado ou, se o registro já estiver carregado, o uso#length
.count
para comsize
base nos seus comentários. Mais informações em: dev.mensfeld.pl/2014/09/…Funciona no Rails 5 e é independente do DB:
Isso no seu controlador:
Obviamente, você pode colocar isso em uma preocupação, como mostrado aqui .
app / modelos / preocupações / randomable.rb
então...
app / models / book.rb
Então você pode usar simplesmente fazendo:
ou
fonte
Você pode usar sample () no ActiveRecord
Por exemplo
Fonte: http://thinkingeek.com/2011/07/04/easily-select-random-records-rails/
fonte
sample
não está no ActiveRecord, a amostra está na matriz. api.rubyonrails.org/classes/Array.html#method-i-sampleSe estiver usando o Oracle
Resultado
fonte
Recomenda vivamente esta gema para registros aleatórios, projetados especialmente para tabelas com muitas linhas de dados:
https://github.com/haopingfan/quick_random_records
Todas as outras respostas apresentam um desempenho ruim com um banco de dados grande, exceto esta gema:
4.6ms
totalmente.User.order('RAND()').limit(10)
custo de resposta aceito733.0ms
.offset
abordagem custou245.4ms
totalmente.User.all.sample(10)
custo da abordagem573.4ms
.Nota: Minha tabela possui apenas 120.000 usuários. Quanto mais registros você tiver, mais enorme será a diferença de desempenho.
ATUALIZAR:
Desempenho na tabela com 550.000 linhas
Model.where(id: Model.pluck(:id).sample(10))
custo1384.0ms
gem: quick_random_records
só custa6.4ms
totalmentefonte
Uma maneira muito fácil de obter vários registros aleatórios da tabela. Isso faz duas consultas baratas.
Model.where(id: Model.pluck(:id).sample(3))
Você pode alterar o "3" para o número de registros aleatórios que desejar.
fonte
Acabei de encontrar este problema desenvolvendo um pequeno aplicativo em que desejava selecionar uma pergunta aleatória do meu banco de dados. Eu usei:
E está funcionando bem para mim. Não posso falar sobre como o desempenho de bancos de dados maiores, pois esse é apenas um aplicativo pequeno.
fonte
shuffle[0]
)