可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
User.find(:all, :order => "RANDOM()", :limit => 10)
was the way I did it in Rails 3.
User.all(:order => "RANDOM()", :limit => 10)
is how I thought Rails 4 would do it, but this is still giving me a Deprecation warning:
DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (e.g. `Post.where(published: true).to_a`).
回答1:
You'll want to use the order
and limit
methods instead. You can get rid of the all
.
For PostgreSQL and SQLite:
User.order("RANDOM()").limit(10)
Or for MySQL:
User.order("RAND()").limit(10)
回答2:
As the random function could change for different databases, I would recommend to use the following code:
User.offset(rand(User.count)).first
Of course, this is useful only if you're looking for only one record.
If you wanna get more that one, you could do something like:
User.offset(rand(User.count) - 10).limit(10)
The - 10
is to assure you get 10 records in case rand returns a number greater than count - 10.
Keep in mind you'll always get 10 consecutive records.
回答3:
I think the best solution is really ordering randomly in database.
But if you need to avoid specific random function from database, you can use pluck
and shuffle
approach.
For one record:
User.find(User.pluck(:id).shuffle.first)
For more than one record:
User.where(id: User.pluck(:id).sample(10))
回答4:
I would suggest making this a scope as you can then chain it:
class User < ActiveRecord::Base
scope :random, -> { order(Arel::Nodes::NamedFunction.new('RANDOM', [])) }
end
User.random.limit(10)
User.active.random.limit(10)
回答5:
While not the fastest solution, I like the brevity of:
User.ids.sample(10)
The .ids
method yields an array of User IDs and .sample(10)
picks 10 random values from this array.
回答6:
For MYSQL this worked for me:
User.order("RAND()").limit(10)
回答7:
Strongly Recommend this gem for random records, which is specially designed for table with lots of data rows:
https://github.com/haopingfan/quick_random_records
All other answers perform badly with large database, except this gem:
- quick_random_records only cost
4.6ms
totally.
- the accepted answer
User.order('RAND()').limit(10)
cost 733.0ms
.
- the
offset
approach cost 245.4ms
totally.
- the
User.all.sample(10)
approach cost 573.4ms
.
Note: My table only has 120,000 users. The more records you have, the more enormous the difference of performance will be.
UPDATE:
Perform on table with 550,000 rows
Model.where(id: Model.pluck(:id).sample(10))
cost 1384.0ms
gem: quick_random_records
only cost 6.4ms
totally
回答8:
You could call .sample
on the records, like: User.all.sample(10)
回答9:
Here's a quick solution.. currently using it with over 1.5 million records and getting decent performance. The best solution would be to cache one or more random record sets, and then refresh them with a background worker at a desired interval.
Created random_records_helper.rb
file:
module RandomRecordsHelper
def random_user_ids(n)
user_ids = []
user_count = User.count
n.times{user_ids << rand(1..user_count)}
return user_ids
end
in the controller:
@users = User.where(id: random_user_ids(10))
This is much quicker than the .order("RANDOM()").limit(10)
method - I went from a 13 sec load time down to 500ms.