【发布时间】:2018-02-26 16:30:27
【问题描述】:
我正在开发一个简单的应用程序来返回随机选择的exercises,每个bodypart 一个。
bodypart 是 Exercise 模型上的索引 enum 列。 DB 是 PostgreSQL。
以下实现了我想要的结果,但感觉非常低效(每个bodypart 访问一次数据库):
BODYPARTS = %w(legs core chest back shoulders).freeze
@exercises = BODYPARTS.map do |bp|
Exercise.public_send(bp).sample
end.shuffle
因此,这会为每个 bodypart 提供一个随机的 exercise,并在最后混淆顺序。
我还可以将所有练习存储在内存中并从中选择;但是,我想这会扩展得非常可怕(目前只有十几个种子记录)。
@exercises = Exercise.all
BODYPARTS.map do |bp|
@exercises.select { |e| e[:bodypart] == bp }.sample
end.shuffle
基准测试表明select 方法在小范围内更有效:
Queries: 0.072902 0.020728 0.093630 ( 0.088008)
Select: 0.000962 0.000225 0.001187 ( 0.001113)
MrYoshiji's answer: 0.000072 0.000008 0.000080 ( 0.000072)
我的问题是是否有一种有效的方法来实现这种输出,如果有,这种方法可能是什么样子。理想情况下,我想将其保留为单个数据库查询。
很高兴使用 ActiveRecord 或直接在 SQL 中编写此内容。任何想法都非常感谢。
【问题讨论】:
-
尝试以下操作:
Exercise.group(:bodypart).select('distinct on (bodypart) *').order('bodypart, random()); -
Star @MrYoshiji - 我必须将
:id添加到组子句中,即Exercise.group(:bodypart, :id).select('distinct on (bodypart) *').order('bodypart, random()')以克服以下错误:ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "exercises.id" must appear in the GROUP BY clause or be used in an aggregate function。我会将它插入基准代码并查看它的比较情况,但这看起来只是一张票 - 如果你弹出一个很高兴接受你的答案!
标签: sql ruby-on-rails ruby postgresql activerecord