所以,我发现了几个在Rails 2中查找随机记录的例子 - 首选方法似乎是:
Thing.find :first, :offset => rand(Thing.count)
作为一个新手,我不确定如何使用Rails 3中的新查找语法构建它。
那么,找到随机记录的“Rails 3 Way”是什么?
答案 0 :(得分:214)
Thing.first(:order => "RANDOM()") # For MySQL :order => "RAND()", - thanx, @DanSingerman
# Rails 3
Thing.order("RANDOM()").first
或
Thing.first(:offset => rand(Thing.count))
# Rails 3
Thing.offset(rand(Thing.count)).first
实际上,在Rails 3中,所有示例都可以使用。但是使用顺序RANDOM
对于大表来说是相当慢的,但是更多的是sql风格的
UPD。您可以在索引列(PostgreSQL语法)上使用以下技巧:
select *
from my_table
where id >= trunc(
random() * (select max(id) from my_table) + 1
)
order by id
limit 1;
答案 1 :(得分:29)
我正在开发一个项目( Rails 3.0.15,ruby 1.9.3-p125-perf ),其中db位于 localhost 中,而users表有一点超过 100K记录。
使用
按兰德()订购
很慢
User.order( “RAND(ID)”)。第一
变为
SELECT
users
。* FROMusers
ORDER BY RAND(id)LIMIT 1
并从 8 到 12秒进行回复!!
Rails日志:
用户加载(11030.8ms)SELECT
users
。* FROMusers
ORDER BY RAND() 限制1
来自mysql的解释
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 110165 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
您可以看到没有使用索引( possible_keys = NULL ),创建临时表并需要额外的传递来获取所需的值( extra = Using temporary; Using文件排序强>)。
另一方面,通过将查询拆分为两部分并使用Ruby,我们在响应时间方面有了合理的改进。
users = User.scoped.select(:id);nil
User.find( users.first( Random.rand( users.length )).last )
(;控制台使用时为零)
Rails日志:
用户加载(25.2ms)SELECT id FROM
users
用户加载(0.2ms)SELECTusers
。* FROMusers
WHEREusers
。id
= 106854 LIMIT 1
和mysql的解释证明了原因:
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| 1 | SIMPLE | users | index | NULL | index_users_on_user_type | 2 | NULL | 110165 | Using index |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
我们现在只能使用索引和主键,并且工作速度提高了大约500倍!
更新:
正如icantbecool在评论中所指出的,如果表中有删除的记录,上述解决方案存在缺陷。
其中的解决方法可以是
users_count = User.count
User.scoped.limit(1).offset(rand(users_count)).first
转换为两个查询
SELECT COUNT(*) FROM `users`
SELECT `users`.* FROM `users` LIMIT 1 OFFSET 148794
并在大约500ms内运行。
答案 2 :(得分:12)
如果使用Postgres
User.limit(5).order("RANDOM()")
如果使用MySQL
User.limit(5).order("RAND()")
在这两种情况下,您都会从“用户”表中随机选择5条记录。以下是控制台中显示的实际SQL查询。
SELECT * FROM users ORDER BY RANDOM() LIMIT 5
答案 3 :(得分:11)
我做了一个rails 3 gem,这样做可以在大型表上表现更好,并允许你链接关系和范围:
https://github.com/spilliton/randumb
(编辑):我的gem的默认行为基本上使用与上面相同的方法,但是你可以选择使用旧方法:)
答案 4 :(得分:6)
实际上发布的许多答案在相当大的表(100多万行)上表现不佳。随机排序很快就需要几秒钟,而对表格进行计数也需要很长时间。
在这种情况下,对我来说效果很好的解决方案是将RANDOM()
与where条件一起使用:
Thing.where('RANDOM() >= 0.9').take
在一个行超过一百万的表上,此查询通常需要不到2毫秒。
答案 5 :(得分:5)
我们走了
#in your initializer
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
end
end
Model.random #returns single random object
或第二个想法是
module ActiveRecord
class Base
def self.random
order("RAND()")
end
end
end
用法:
Model.random #returns shuffled collection
答案 6 :(得分:4)
这对我来说非常有用,但我需要更多的灵活性,所以这就是我所做的:
案例1:查找一个随机记录 来源:trevor turk site
将其添加到Thing.rb模型
def self.random
ids = connection.select_all("SELECT id FROM things")
find(ids[rand(ids.length)]["id"].to_i) unless ids.blank?
end
然后在你的控制器中你可以调用这样的东西
@thing = Thing.random
案例2:查找多个随机记录(无重复) 来源:无法记住
我需要找到10个没有重复的随机记录,所以这就是我发现的工作
在您的控制器中:
thing_ids = Thing.find( :all, :select => 'id' ).map( &:id )
@things = Thing.find( (1..10).map { thing_ids.delete_at( thing_ids.size * rand ) } )
这将找到10个随机记录,但值得一提的是,如果数据库特别大(数百万条记录),这将不是理想的,性能将受到阻碍。对于我来说,它会表现出几千条记录。
答案 7 :(得分:4)
从列表中随机选择项目的Ruby方法是sample
。想要为ActiveRecord创建一个高效的sample
,并根据以前的答案,我使用了:
module ActiveRecord
class Base
def self.sample
offset(rand(size)).first
end
end
end
我将其放在lib/ext/sample.rb
中,然后将其加载到config/initializers/monkey_patches.rb
:
Dir[Rails.root.join('lib/ext/*.rb')].each { |file| require file }
答案 8 :(得分:3)
适用于Rails 5并且与数据库无关:
这在您的控制器中:
@quotes = Quote.offset(rand(Quote.count - 3)).limit(3)
当然,您可以将其置于here所示的问题中。
module Randomable
extend ActiveSupport::Concern
class_methods do
def random(the_count = 1)
records = offset(rand(count - the_count)).limit(the_count)
the_count == 1 ? records.first : records
end
end
end
...然后
class Book < ActiveRecord::Base
include Randomable
end
然后你可以简单地使用:
Books.random
或
Books.random(3)
答案 9 :(得分:2)
您可以在ActiveRecord中使用sample()
E.g。
def get_random_things_for_home_page
find(:all).sample(5)
end
来源:http://thinkingeek.com/2011/07/04/easily-select-random-records-rails/
答案 10 :(得分:1)
如果使用Oracle
User.limit(10).order("DBMS_RANDOM.VALUE")
输出
SELECT * FROM users ORDER BY DBMS_RANDOM.VALUE WHERE ROWNUM <= 10
答案 11 :(得分:1)
强烈推荐这个gem用于随机记录,这是专为具有大量数据行的表而设计的:
https://github.com/haopingfan/quick_random_records
所有其他答案在大型数据库中都表现不佳,除了这个gem:
答案 12 :(得分:-2)
从表中获取多个随机记录的一种非常简单的方法。这使得2个便宜的查询。
Model.where(id: Model.pluck(:id).sample(3))
您可以将“3”更改为您想要的随机记录数。
答案 13 :(得分:-5)
我刚刚遇到这个问题开发一个小应用程序,我想从我的数据库中选择一个随机问题。我用过:
@question1 = Question.where(:lesson_id => params[:lesson_id]).shuffle[1]
它对我有用。我不能谈论大型数据库的性能如何,因为这只是一个小应用程序。