has_and_belongs_to_many其他记录不存在的地方

时间:2013-07-02 15:57:13

标签: ruby-on-rails ruby-on-rails-3

我们有

has_and_belongs_to_many :questions #on game.rb
has_and_belongs_to_many :games # on question.rb

我必须找到所有未分配给游戏的问题。所以,我正在做

t = []
Question.includes(:games).all.each { |q| t <<  q.id  if !q.games.present? }
puts t.size

但我们有30,000多条记录,因此处理上述查询需要花费太多时间。如何应对这种情况?是否有优化上述查询,以便我的服务器可能不会出现内存或其他灾难 感谢

2 个答案:

答案 0 :(得分:1)

如果可以安全地假设连接表中没有未分配给游戏的问题的行,那么:

t = Question.where("not exists (select null from games_questions gq where gq.question_id = questions.id)").count

如果你需要实际的问题对象,那么当然要省略计数。

您的查询类似于:

select count(*)
from   questions
where  not exists (
         select null
         from   games_questions gq
         where  gq.question_id = questions.id);

它计算问题表中没有从相关子查询返回的行的所有行(因此,相关子查询的select子句中的内容无关紧要,我通常使用NULL)。 / p>

因此,对于id = 5的问题,只返回使用question_id = 5找不到games_questions表中的行的行。

虽然天真的查询优化器可能会将此实现为问题的完整表扫描和每行的子查询执行,但更复杂的优化器会将此识别为反连接,并且实现效率更高。在Oracle中,它很可能是一个散列反连接,尽管这取决于每个表中的行数。如果问题有10行且games_questions有1,000,000并且games_questions.question_id已被编入索引,那么您可能会看到更天真的执行计划,使用嵌套循环来探测问题中每行的games_questions表。

答案 1 :(得分:0)

会不会

Question.joins(:games)

做你想做的事吗?