繁体   English   中英

您如何有效地(以与数据库无关的方式)从表中选择随机记录?

[英]How do you efficiently (in a DB independent manner) select random records from a table?

这似乎是一个非常简单的问题,但是并没有像我预期的那么简单。

我有一个拥有俱乐部会员的俱乐部,我想从俱乐部随机抽出两名成员。

使用RANDOM()

一种方法是使用随机排序:

club.members.find(:all, :order => 'RANDOM()').limit(2)

但是,这对于SqLite(开发人员数据库)和Postgres(生产人员)是不同的,因为在MySql中,命令是RAND()

尽管我可以开始为此编写一些包装器,但我感到它尚未完成并且似乎不是ActiveRecord的一部分这一事实告诉了我一些信息,而RANDOM可能不是正确的选择。

使用索引直接拉出项目

执行此操作的另一种方法是按顺序提取集,然后从中选择随机记录:

首先,我们需要生成一个与成员相对应的两个唯一索引的序列:

all_indices = 1..club.members.count
two_rand_indices = all_indices.to_a.shuffle.slice(0,2)

这给出了一个带有两个保证唯一且随机的索引的数组。 我们可以使用这些索引提取记录

@user1, @user2 = Club.members.values_at(*two_rand_indices)

最好的方法是什么?

尽管第二种方法看起来不错,但我也觉得我可能会遗漏某些东西,并且可能使一个简单的问题变得复杂。 我显然不是第一个解决此问题的人,那么通过它的最佳,最有效的SQL路由是什么?

您的第一种方法的问题在于,它使用不可索引的表达式对整个表进行排序,仅占用两行。 这不能很好地扩展。

第二种方法的问题是相似的,如果表中有10 9行,则将从to_a生成一个大数组。 这将需要大量的内存和时间来洗牌。

另外,通过使用values_at ,您是否不假设每个主键值从1开始都有一行,没有间隔? 你不应该这么认为。

我推荐的是:

  1. 计算表中的行。

     c = Club.members.count 
  2. 在1和计数之间选择两个随机数。

     r_a = 2.times.map{ 1+Random.rand(c) } 
  3. limit和offset查询表。
    不要使用ORDER BY ,而只需依赖RDBMS的任意顺序。

     for r in r_a row = Club.members.limit(1).offset(r) end 

也可以看看:

MySQL中的RAND()函数:

ORDER BY RAND() LIMIT 4

当上面是查询中的最后一个子句时,它将随机选择4行。

尝试使用randumb gem,它实现了您提到的第二种方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM