Ruby on Rails中如何确保从Question表获取3条唯一随机记录?
嘿,我来帮你理清这个问题~你的当前方法其实没法保证返回3条唯一的记录,哪怕加了uncached也不行,我给你拆解原因,再说说靠谱的解决办法:
为什么现有方法不靠谱?
uncached只是让Active Record不缓存单次查询的结果,但每次调用Question.order("RANDOM()").first都是独立的数据库查询——数据库每次都会重新做随机排序,完全有可能重复选中之前已经取到的记录。比如如果你的Question表只有3条数据,运气不好的话,循环里可能连续两次拿到同一条,最后@randquestion里就会出现重复项。而且这种循环多次查询数据库的方式,效率也很低,数据量越大越明显。
正确的实现方式
其实你一开始看到的写法就是最优解!直接让数据库一次性返回3条唯一的随机记录就好,根本不需要循环:
def selectr @randquestion = Question.order("RANDOM()").limit(3) end
PostgreSQL的ORDER BY RANDOM()会给全表数据随机排序,LIMIT 3直接取前3条,这些记录天然就是唯一的——因为数据库不会返回重复的行(除非你的表本身有重复数据,但那是数据层面的问题了)。
额外优化(针对大数据量表)
如果你的Question表有几万甚至几十万条数据,ORDER BY RANDOM()可能会因为全表排序有点慢,这时候可以用PostgreSQL的TABLESAMPLE来更高效地取随机数据,比如:
def selectr @randquestion = Question.from("questions TABLESAMPLE BERNOULLI(10)").limit(3) end
这里的10表示随机取10%的数据,再从中取前3条,效率会高很多。但要注意,如果表很小,可能取不够3条,这时候可以加个判断或者调整采样比例。如果表数据量不大,直接用ORDER BY RANDOM().limit(3)就足够了。
内容的提问来源于stack exchange,提问作者Amulya Agarwal

