Debugging Performance Problems In Your Views | GoRails - GoRails
Hi Chris, this issue is called N+1 problem and one of the ways to face it is by doing "eager loading" because sometimes you still need to use your step object in the view, so in the controller it's just simple as doing something like that : @steps = Step.all.includes(:course), you can even go deeper : I don't remember the syntax exactly but it's something like that steps.all.includes(course: [:other, :category, ....]), sometimes when you need more complex query you should use join instead of includes... I had the issue a long time ago when I wanted to implement an activity feed where every post has to bring the author and the comments for that post and also the users who write the comments...
Well, we actually eager load the sections, steps and privacy settings at the beginning through the course. That's all done and was the obvious thing to look at for performance, but the real bug here is more subtle in that we've loaded the object already but weren't referencing it correctly.
Those are all equally important in building performant responses though!
I was just going to give you a heads up: I re-recorded this episode and think it's a lot more clear this time. :) Thanks for your help because it definitely needed to be cleaned up!
This episode is more clear, I can see why you had that performance problem, your solution is the best in this case, but I think I know why step.course does trigger the database each time because I deal many times with eager loading in the past! let's imagine you only eager load "steps" like this @course.sections.includes(:steps) , in this case the requests are : 1- it fetch * from sections where the course_id equal @course.id then 2- it fetch * from steps for **each** section (but it doesn't fetch the course for each step, so just I may told you before, if you do steps: :product which I now it's redundant and inefficient because you already have @course then you will not have the performance problem); I don't know if my explanation is clear but in general : steps are loaded for each section, so: @course.sections.find(3).steps or even @course.sections.find(3).steps.find(5) will not trigger the database, but if you try to do the inverse and access @course from a step then obviously it will trigger the database. I hope I am not confusing this time!
Hey Chris! I'm really excited for the Rails from Scratch series. If you can include how gems are incorporated into a Rails app from outside of the project's folder, that would be awesome. Thanks for doing this!
Gems are definitely a topic I want to cover. There are a lot of little things related to that (like why do we have Bundler and how does it help?) so I'll make sure there's at least one episode on this gem related things.
Hey Chris,
What ever happened to that Rails from Scratch series? Not doing it again or is it postponed until a later date?
I'm still planning on it! I just need to get started honestly. What I wanted to do was wrap up my vlogs about simple-calendar and then hop into that after I'm done. Those should be finished in the next couple days.
Hi Chris,
What would you recommend to optimize a partial that is loaded from a helper? You see, I have this partial where I have to call many times 'patient.evolution_notes' but it's querying the database many times. Is there a way I could optimize it, since there's no controller for that specific partial?
Thanks
I would say try your best to eager load as many of the subrecords as you can so that you're not querying as much. You may be able to cache that in the controller instead of the partial and save some query time that way.