简体   繁体   中英

Rails N+1 query with has_many association

The model relationship is

section has_many :sections
section belong_to :section
section has_many :questions
question_set has_many :questions, :through => :question_sets_questions

I encounter N+1 query problem, but I don't know how to figure it out.

Here is code

def test
  question_set_id = params[:qset_id].to_i
  q_ids = QuestionSetsQuestion.where(:question_set_id => question_set_id).pluck(:question_id)
  questions = Question.where(:id => q_ids).includes(:section)
  questions.each do |q|
    section = {id: q.section.id, name: q.section.name}
    parent_section = q.section.section rescue nil
    p parent_section.id
  end
end

The bullet gem said

N+1 Query detected
  Section => [:section]
  Add to your finder: :include => [:section]
N+1 Query method call stack

Do I put the includes wrongly?

Update

Thanks @Deepak, .includes(section: :section) can solve two layers of sections. But actually I got three hierarchies of sections. The original code looks like

questions.each do |q|
  section = {id: q.section.id, name: q.section.name}
  parent_section = q.section.section rescue nil
  while parent_section.present?
    section = {id: parent_section.id, name: parent_section.name, children: [section]}
    parent_section = parent_section.section rescue nil
  end
  p section 
end

first thing the associations are really confusing.

I think you are calling two hierarchies of sections on question, so changing this line should work

questions = Question.where(:id => q_ids).includes(section: :section)

You are accessing the parent section of q.section so we need to include that as well

parent_section = q.section.section rescue nil

EDIT

Its getting messier I am not sure if you should do this but i think this will solve the problem

questions = Question.where(:id => q_ids).includes(section: [section: :section])

instead this code:

  questions.each do |q|
    section = {id: q.section.id, name: q.section.name}
    parent_section = q.section.section rescue nil
    p parent_section.id
  end

put one query and iterate over its

parent_sections = Section.joins(sections: :questions).where(questions: {id:  questions.pluck(:id)})
parent_sections.each { |section| p section.id }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM