[LRUG] N+1

Simon Coffey simon at urbanautomaton.com
Tue Aug 4 04:28:49 PDT 2020


Hey Andy,

I think the problem might be that eager loading is applied to specific
associations, and the ones you're applying eager loading to aren't the ones
that you're using to perform your reads.

Specifically, with `some_beta_scope.includes(gammas: :deltas)` you're eager
loading the `Beta#gammas` and `Gamma#deltas` associations, but in your view
you're using `Beta#deltas` and `Delta#gamma` to actually load the
data. (possibly-unhelpful
illustration <http://screenshots.urbanautomaton.com/20200804-p79pj.png>)

You'd either need to rewrite the eager load to match your access pattern
(`some_beta_scope.includes(deltas: :gamma)`, I *think*), or rewrite the
loop to match the eager loading, e.g.

- @betas.each do |beta|
  = beta.name
  - beta.gammas.each do |gamma|
    - gamma.deltas.each do |delta|
      = delta.name
      = gamma.name <http://delta.gamma.name/>

Does that work?

Cheers,
Simon

On Tue, 4 Aug 2020 at 12:14, Andrew Stewart <boss at airbladesoftware.com>
wrote:

> Hello LRUG!
>
> I am having trouble getting rid of database calls to read intermediate
> objects in a hierarchy.
>
> I have some models like this:
>
>     class Alpha < ApplicationRecord
>       has_many :betas
>     end
>
>     class Beta < ApplicationRecord
>       belongs_to :alpha
>       has_many :gammas
>       has_many :deltas, through: :gammas
>     end
>
>     class Gamma < ApplicationRecord
>       belongs_to :beta
>       has_many :deltas
>     end
>
>     class Delta < ApplicationRecord
>       belongs_to :gamma
>     end
>
> And a controller action like this:
>
>     alpha = Alpha.first
>     @betas = alpha.betas
>                   .joins(gammas: :deltas)  # exclude betas without deltas
>                   .includes(gammas: :deltas)
>                   .distinct
>                   .alphabetical
>
> And a view (pseudocode):
>
>     - @betas.each do |beta|               # loads the @betas relation once
> as expected
>       = beta.name
>       - beta.deltas.each do |delta|       # [A] SQL query to get the
> beta's deltas (once per beta)
>         = delta.name
>         = delta.gamma.name                # [B] SQL query to get the
> delta's gamma (once per delta)
>
> It seems to me I should be able to avoid the nested queries, [A] and [B],
> because the @betas relation includes the gammas and deltas, but I haven't
> succeeded yet.
>
> Alternatively, in the console:
>
>     beta = Beta.first
>     beta.deltas.first.gamma.name  # expected 1 query; actually 2
>
> I'm using Rails 6.0.3.1 and Ruby 2.7.
>
> Any pointers would be much appreciated!
>
> Many thanks,
>
> Andy Stewart
>
> _______________________________________________
> Chat mailing list
> Chat at lists.lrug.org
> Archives: http://lists.lrug.org/pipermail/chat-lrug.org
> Manage your subscription: http://lists.lrug.org/options.cgi/chat-lrug.org
> List info: http://lists.lrug.org/listinfo.cgi/chat-lrug.org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lrug.org/pipermail/chat-lrug.org/attachments/20200804/62ae28bb/attachment.html>


More information about the Chat mailing list