2013-07-02 45 views
1

我們有has_and_belongs_to_many而其他記錄不存在

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條記錄,因此正在採取太多的時間來處理上面的查詢。如何處理這種情況?無論如何要優化上述查詢,以便我的服務器不會出現內存不足或其他災難。
感謝

+0

問題是,上面不是查詢。你在Ruby中瀏覽對象是一件很愚蠢的事情。 –

+0

加入表的名稱是什麼? –

+0

@MichaelSzyndel,它遵循默認約定,所以我們有表格「遊戲」,「問題」和「遊戲問題」。 –

回答

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

+0

萬分感謝。它快了10倍。但如果您不介意,請您解釋一下這個問題。 –

0

不會

Question.joins(:games)

你想要做什麼?

+0

它會做相反的事情 - 分配給遊戲的所有問題。 –

+0

啊我看到了,我誤解了你的帖子。對於那個很抱歉。 – gregates

相關問題