简体   繁体   中英

How to avoid N+1 query

I have the following models:

  • User
  • Ability
  • PricingRule

defined with the following relationships:

  • user has many pricing rules
  • ability has one pricing rule

在此输入图像描述

The idea is to fetch all abilities matching some criteria and for each, fetch its pricing rule. However a custom pricing rule for a particular ability can be defined on a per user basis.

Currently I fetch all matching abilities and iterate on them to either:

  • try to find a current ability matching a user's pricing rule
  • or default to the ability's pricing rule

I am using Rails and ActiveRecord and here what I have so far:

user = User.first
Ability.all.map do |a|
  user.pricing_rules.matching_ability(a).first || a.pricing_rule
end

Per user pricing rule customization should be done on demand by the business. The common workflow is to get the pricing rule from the abilities.

Any ideas or help to get me on the right track would be much appreciated.

EDIT:

Where the matching_ability implementation is as follow:

def self.matching_ability(ability)
  where(name: ability.name)
end

You can "eager load" to avoid N+1 queries like so:

user = User.includes(pricing_rules: :abilities).first
Ability.includes(:pricing_rule).map do |a|
  user.pricing_rules.matching_ability(a).first || a.pricing_rule
end

You should see in the SQL generated that this adds a LEFT OUTER JOIN to your queries, so ActiveRecord is loading the associated records in just the two queries. In particular, the user will be loaded with its pricing_rules and the abilities on each pricing_rule , and the abilities will be loaded with their pricing_rules .

However, implementing matching_ability using where may generate additional queries, returning you to the N+1 problem. To take advantage of the "eager load" in the first query, you may need to refactor to:

self.matching_ability(ability)
  select{|a| a.name == ability.name}
end

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