1

我们有

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 多条记录,因此处理上述查询需要花费太多时间。如何处理这种情况?无论如何要优化上述查询,这样我的服务器就不会出现内存不足或其他灾难。
谢谢

4

2 回答 2

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)。

因此,对于 id = 5 的问题,只有在 games_questions 表中找不到 question_id = 5 的行时才会返回该行。

尽管幼稚的查询优化器可能将其实现为对问题的全表扫描并为每一行执行子查询,但更复杂的优化器会将其识别为反连接并更有效地实现。在 Oracle 中,它可能是哈希反连接,尽管这取决于每个表中的行数。如果问题有 10 行,games_questions 有 1,000,000 行,并且 games_questions.question_id 被索引,您可能会看到更简单的执行计划,它使用嵌套循环来探测问题中每一行的 games_questions 表。

于 2013-07-02T16:27:35.063 回答
0

惯于

Question.joins(:games)

做你想做的事?

于 2013-07-02T16:26:36.960 回答