如何用包含 - Rails解决n + 1查询问题

时间:2016-06-12 12:16:45

标签: ruby-on-rails performance

我使用bullet gem找出我的应用有哪些n + 1查询问题,结果发现我有3个问题:

  

用户:检测到Rashed N + 1查询Sale => [:shop]加入你的发现者:   :includes => [:shop]用户:检测到Rashed N + 1查询Shop => [:商场]   添加到您的finder :: includes => [:malls] user:Rashed N + 1 Query   检测到Shop => [:categories]添加到您的finder :: includes =>   [:类别]

问题是我不确定如何使用包含解决问题,因为我的模型与彼此相关联。我有4个型号,销售,商店,商城和类别。这些是我的模型的关联:

class Shop < ActiveRecord::Base
    has_many :categorizations
    has_many :categories, :through => :categorizations
    has_many :mall_shops
    has_many :malls, :through => :mall_shops
    has_many :sales, dependent: :destroy
end

class Sale < ActiveRecord::Base
    belongs_to :shop
end

class Mall < ActiveRecord::Base
    has_many :mall_shops
    has_many :shops, :through => :mall_shops
    has_many :sales, :through => :shops
end

class Category < ActiveRecord::Base
    has_many :categorizations
    has_many :shops, :through => :categorizations
    has_many :sales, :through => :shops
end

在我的销售索引页面中,我显示所有销售记录,每个销售记录属于一个商店,每个商店有许多类别和许多商场。对于显示的每个销售记录,我都会遍历Sale&Shop的商店所属的所有商场和类别(用于过滤目的)。这是我的销售索引页面中的相关代码:

 <% @sales.each do |sale| %>
  <div class="<% sale.shop.malls.each do |m| %> mall<%= m.id %><% end %><% sale.shop.categories.each do |c| %> category<%= c.id %><% end %>">

.
.

end

我的销售总监:

class SalesController < ApplicationController
 def index
    @malls = Mall.all.order('name ASC')
    @categories = Category.all.order('category_type ASC')
    @shops = Shop.all
    @sales = Sale.where('offer_end >= ?', Date.today).order('offer_end ASC')
  end
end

那么解决我遇到的n + 1查询问题的最佳方法是什么?为了更好地了解我的应用程序,这是我建立的网站:www.shopwatchkw.com

1 个答案:

答案 0 :(得分:3)

在控制器中,试试这个:

@sales = Sale.includes(shop: [:categories, :malls])
             .where('offer_end >= ?', Date.today)
             .order('offer_end ASC')

基本上,您从顶级模型开始,并通过includes语句急切加载其子级。 Bullet告诉你添加.includes(:shop),之后,它可能会告诉你关于:categories:mails的相同内容,它们是Shop上的子查询,正如你所描述的那样。

Read more on eager loading in Rails