简体   繁体   中英

N+1 issue when updating a model with a relationship

I have a N+1 problem which I cannot solve. I have a sample app hosted here that shows the issue: https://github.com/davidmles/question_parts

This is how it works:

There are 4 models: question, question_part, answer, and answer_part. A question has N parts, and also N answers. An answer has N parts. And an answer part belongs to an answer and to a question part (the one is answering).

An answer can be a draft or published. A draft does not need to have all its parts answered, while a published answer does need them answered.

The problem:

When an answer is created, but not all its parts are answered, and I try to publish it, validation will fail and the edit form will be shown again. When showing that edit form after validation failed, there will be a N+1 problem, as answer parts will load the corresponding question parts without eager loading them.

I have tried to eager load them, but then the edit form will not show the proper error.

How could I solve this? I have added more information in app's readme file, as well as steps to guide on seeing the problem: https://github.com/davidmles/question_parts/blob/master/README.md

Bad news: it seems that ActiveRecord does not play nicely with #includes in collection associations. And actually you cannot hack it because it does not persist relation object ( here ).

Good news: I found some workaround.

Add has_many :question_parts, through: :parts to your Answer model. After that use this finder in answers_controller: @answer = Answer.preload(:question_parts).where(id: params[:id]).first . Occasionally bullet gem does not like that (it says unused eager loading blabla but it's not true) but there is no N + 1 query and the form works fine.

Just to complement Flash Gordon's answer, the query could also be written like this:

@answer = Answer.preload(parts: [:question_part]).where(id: id).first

So, no modification to Answer is required.

Also, using includes in place of preload seems to work (Rails chooses the right strategy in this case).

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