Avoid n+1 query on Surveys#5813
Avoid n+1 query on Surveys#5813armandfardeau wants to merge 4 commits intodecidim:developfrom armandfardeau:fix/n+1-query-on-surveys
Conversation
microstudi
left a comment
There was a problem hiding this comment.
Thanks for this @armandfardeau .
I'd like to provide more information about the problem here, as I think it may be something to take into account in other situations.
The main problem here is the use of the Rectify::forms object when using the .from_model method. What this method does is to map all the specified attributes into the model, if the model has a a one-to-many relationship (as are the answers for a questionnaire), you've end with a SELECT * FROM answers SQL query (unless is scoped by default I guess).
using the map_model method inside the definition of the Form class doesn't help here because, this method is executed AFTER building the object, so it does not replaces it. You can see the original code of Rectify::Form that does that here: https://github.com/andypike/rectify/blob/6bb7dcb563fccb4dfee44936ebb7b19e11d18473/lib/rectify/build_form_from_model.rb#L8
Finally, I see that the solution proposed here avoids using .from_model so the build mechanism won't be triggered. This causes, however, to extract part of the functionality done in in the QuestionnaireForm class to the controller, making everything a little bit more untidy. Just thinking out-loud, but maybe this could be solved by using another name than :answers for the attributes in the form?
I like the opinions of people like @mrcasals or @tramuntanal here, do you see this as the best option to proceed? I my opinion, this is important because it can be happening in other places of the Decidim as well, and is extremely easy to overlook. Establishing a generic procedure of how to handle this cases would be very helpful.
|
Great catch @armandfardeau 🎉 |
|
@microstudi I was thinking about the answers outside the form and I must admit that I am not satisfied with the solution I came up with, but I had to correct it quickly and I had already taken too much time. Do you have an idea? |
|
Also, if anyone understands why the proposal tests don't pass... I'm in. |
My first idea is just not to use the name |
could be this? #5812 |
Fell free to add this if you want, unfortunately, I don't have time to push further. |
Great catch thanks. |
|
Hi! In case it's helpful, in other projects I've used https://github.com/flyerhzm/bullet to help detect N+1 queries 😄 |
This one is provided by Query Diet |
|
@armandfardeau I've made another implementation to fix this, I think it is simpler. Would you like to check it out? https://github.com/decidim/decidim/pull/5819/files |
This is obviously simpler. Let's go with it. |
🎩 What? Why?
We noticed that the survey component was querying the whole answers table when instantiated.
In
decidim-forms/app/controllers/decidim/forms/concerns/has_questionnaire.rb:The consequence was the questionnaire answers were queried, and replaced by the questions.
For a 3370 answers survey, the number of queries needed to render the form was:
6486 request -> 52680 ms in local env
After this fix it was:
38 request -> 37 ms in local env
related to:
#5697
📋 Subtasks
CHANGELOGentry📷 Screenshots (optional)
before:

After:
