我这里有两个方法,distinct_question_ids和@correct_on_first尝试。我们的目标是向用户展示多少个不同的选择题已经回答是正确的。
第二个让我知道在第一次尝试中正确回答了多少个不同的MCQ。 (用户可以多次尝试MCQ)
现在,当用户回答数千个问题并拥有数千个用户答案时,显示其性能的页面将花费30秒到一分钟的时间来加载。而且我相信这是由于.select方法引起的,但是我不知道如何在不使用.select的情况下替换.select,因为它就像.each
一样循环是否有不引起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
答案 0 :(得分:3)
.pluck
返回一个值数组,而不是ActiveRecord :: Relation。
因此,当您执行distinct_question_ids.select
时,不是调用ActiveRecord的select
,而是调用Array的select
。在该选择项中,您将针对您刚刚采出的每个ID(包括在选择项中被拒绝的ID)针对@user发出全新的查询。
您可以创建一个名为distinct_questions
的查询,该查询返回一个关系(不要采空!),然后在此基础上构建correct_on_first_attempt
,我认为您将避免N + 1个查询。 / p>
遵循以下原则:
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
您需要确保.first实际上是第一次尝试,可能是通过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和.group获得类似的内容。但是...看来您的某些项目要求取决于该序列号,因此,如果您还没有序列号,我建议您添加它。
ps。要解决N + 1个查询,请使用gem bullet。准点。