是。选择和或。凡负责铁轨导致N + 1个查询?

问题描述 投票:3回答:1

我有两种方法在这里,distinct_question_ids和@correct_on_first尝试。我们的目标是向用户展示多少个不同的选择题已经回答是正确的。

第二个将让我知道其中有多少不同的多选题已经在第一次尝试正确回答。 (用户可以尝试MCQ多次)

现在,当用户回答问题成千上万拥有数千用户的答案,页面展示自己的表现正在30秒到一分钟加载。我相信这是由于。选择方法,但我不知道如何替换。选择不使用。选择,因为它循环一样。每

是否有不会导致N + 1的任何方法?

distinct_question_ids = @user.user_answers.includes(:multiple_choice_question).
  where(is_correct_answer: true).
  distinct.pluck(:multiple_choice_question_id)

@correct_on_first_attempt = distinct_question_ids.select { |qid|
  @user.user_answers.
    where(multiple_choice_question_id: qid).first.is_correct_answer
}.count
ruby-on-rails ruby
1个回答
3
投票

.pluck返回值的数组,而不是一个ActiveRecord ::关系。

所以,当你做distinct_question_ids.select你不打电话的ActiveRecord的select,但阵列的select。在这一选择,你发出反对@user每一个你刚摘ID的全新查询 - 包括获得在选择拒绝的。

你可以创建一个查询名为distinct_questions返回的关系(无勇气!),然后建立correct_on_first_attempt关闭的这一点,我想你会避免N + 1个查询。

这些方针的东西:

class UserAnswer < ActiveRecord::Base
   scope :distinct_correct, -> { includes(:multiple_choice_question)
                                   .where(is_correct_answer: true).distinct }

   scope :first_attempt_correct, -> { distinct_correct
                                        .first.is_correct_answer }
end

class User < ActiveRecord::Base
  def good_guess_count
    @correct_on_first_attempt = @user.user_answers.distinct_correct.first_attempt_correct.count
  end
end

你需要保证。首先是实际得到他们的第一次尝试,可能是由ID或created_at排序。

顺便说一句,如果你在UserAnswer明确跟踪尝试次数,你才能真正加强这件事:

class UserAnswer < ActiveRecord::Base
  scope :correct, -> { where(is_correct_answer: true) }
  scope :first_attempt, -> { where(attempt: 1) }
end

class User < ActiveRecord::Base
  def lucky_guess_count
    @correct_on_first_attempt = @user.user_answers.includes(:multiple_choice_question)
                                     .correct.first_attempt.count
  end
end

如果你没有在你的架构中的尝试次数,你可以.order和。集团得到类似的东西。但是......看来你的一些项目需求取决于序列号,所以我建议你加入它,如果你还没有的话。

PS。对于战斗N + 1个查询,使用宝石子弹。这是点。

© www.soinside.com 2019 - 2024. All rights reserved.