47

User.find(:all, :order => "RANDOM()", :limit => 10)是我在 Rails 3 中的做法。

User.all(:order => "RANDOM()", :limit => 10)我认为 Rails 4 会这样做,但这仍然给了我一个弃用警告:

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`).
4

10 回答 10

115

您将需要使用orderandlimit方法。你可以摆脱all.

对于 PostgreSQL 和 SQLite:

User.order("RANDOM()").limit(10)

或者对于 MySQL:

User.order("RAND()").limit(10)
于 2013-06-28T20:39:29.327 回答
40

由于随机函数可能会因不同的数据库而改变,我建议使用以下代码:

User.offset(rand(User.count)).first

当然,这仅在您只查找一条​​记录时才有用。

如果您想获得更多,可以执行以下操作:

User.offset(rand(User.count) - 10).limit(10)

- 10是为了确保您获得 10 条记录,以防 rand 返回大于count - 10的数字。

请记住,您将始终获得 10 条连续记录。

于 2015-01-14T22:53:01.480 回答
23

我认为最好的解决方案是在数据库中随机排序。但是如果你需要避免来自数据库的特定随机函数,你可以使用pluckshuffle方法。

一条记录:

User.find(User.pluck(:id).shuffle.first)

多于一条记录:

User.where(id: User.pluck(:id).sample(10))
于 2016-02-07T16:22:59.407 回答
13

我建议将其设为范围,因为您可以将其链接起来:

class User < ActiveRecord::Base
  scope :random, -> { order(Arel::Nodes::NamedFunction.new('RANDOM', [])) }
end 

User.random.limit(10)
User.active.random.limit(10)
于 2016-06-16T21:03:31.273 回答
8

虽然不是最快的解决方案,但我喜欢简洁:

User.ids.sample(10)

.ids方法产生一个用户 ID 数组,并.sample(10)从该数组中选择 10 个随机值。

于 2016-11-01T09:36:26.830 回答
7

强烈推荐这个 gem 用于随机记录,它是专门为具有大量数据行的表设计的:

https://github.com/haopingfan/quick_random_records

所有其他答案在大型数据库中表现不佳,除了这个 gem:

  1. quick_random_records 只花费4.6ms了全部费用。

在此处输入图像描述

  1. 接受的答案User.order('RAND()').limit(10)成本733.0ms

在此处输入图像描述

  1. offset方法完全成本245.4ms

在此处输入图像描述

  1. 进场User.all.sample(10)成本573.4ms

在此处输入图像描述

注意:我的表只有 120,000 个用户。您拥有的记录越多,性能差异就越大。


更新:

在有 550,000 行的表上执行

  1. Model.where(id: Model.pluck(:id).sample(10))成本1384.0ms

在此处输入图像描述

  1. gem: quick_random_records只花费6.4ms完全

在此处输入图像描述

于 2018-05-18T10:24:24.317 回答
1

对于 MYSQL,这对我有用:

User.order("RAND()").limit(10)
于 2016-03-19T13:29:47.117 回答
0

@maurimiranda 的答案User.offset(rand(User.count)).first不好,如果我们需要获得 10 条随机记录,因为User.offset(rand(User.count) - 10).limit(10)将从随机位置返回 10 条记录的序列,它们不是“完全随机”,对吗?因此,我们需要调用该函数 10 次才能获得 10 个“随机总数”。

除此之外,如果随机函数返回高值,偏移量也不好。如果您的查询看起来像 offset: 10000 和 limit: 20 ,它会生成 10,020 行并丢弃前 10,000 行,这非常昂贵。所以调用 10 次 offset.limit 效率不高。

所以我认为如果我们只想获得一个随机用户,那么User.offset(rand(User.count)).first可能会更好(至少我们可以通过缓存 User.count 来改进)。

但是,如果我们想要 10 个或更多随机用户,那么User.order("RAND()").limit(10)应该会更好。

于 2020-02-11T10:44:04.900 回答
0

您可以调用.sample记录,例如:User.all.sample(10)

于 2018-11-03T13:56:43.223 回答
-4

这是一个快速的解决方案.. 目前使用它有超过 150 万条记录并获得了不错的性能。最好的解决方案是缓存一个或多个随机记录集,然后以所需的时间间隔使用后台工作人员刷新它们。

创建的random_records_helper.rb文件:

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

在控制器中:

@users = User.where(id: random_user_ids(10))

这比方法快得多.order("RANDOM()").limit(10)——我从 13 秒的加载时间缩短到了 500 毫秒。

于 2016-06-07T15:37:42.593 回答