[LRUG] N+1

Andrew Stewart boss at airbladesoftware.com
Tue Aug 4 04:13:20 PDT 2020


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



More information about the Chat mailing list