【问题标题】:Rails query optimization(eliminating n+1 queries)Rails 查询优化(消除 n+1 个查询)
【发布时间】:2014-12-03 05:51:35
【问题描述】:

我正在处理一个项目,有一个复杂的查询需要 10 秒左右才能执行。我意识到有一个 N + 1 查询正在发生,但我是 Rails 新手,我不知道如何解决它。控制器代码是:

def index

    filters = params.slice(:package_type, :guid)
    list = packages
    list = list.where(filters) unless filters.empty?

    respond_to do |format|
      format.html { @packages = list.includes(:classification).order(:priority => :asc) }
      format.json { @packages = list.includes(:classification, {channels: [:classification, :genres]}, :extras).order(:priority => :asc) }
    end
  end

封装模型有

class Package < ActiveRecord::Base
  extend FriendlyId


  belongs_to :classification
  has_many :package_channels
  has_many :channels, -> { order(:priority => :asc, :identifier => :asc) }, through: :package_channels
  has_many :package_extras
  has_many :extras, -> { order(:identifier => :asc) },through: :package_extras

渠道模型有:

class Channel < ActiveRecord::Base

  belongs_to :classification
  has_many :channel_genres
  has_many :genres, through: :channel_genres
  has_many :package_channels
  has_many :packages, through: :package_channels

我还想提一下,过滤器通常是空的。如果我缺少任何信息,请随时发表评论,我会添加它。感谢您的宝贵时间!

这是来自控制器的#packages 方法。

 def packages
    @plan ? @plan.packages : Package
  end

这里是视图:index.json.jbuilder

json.cache! ["cache", "#{params["plan_id"]}_packages_index"] do
  json.array! @packages do |package|
    json.partial! 'packages/package_lean', package: package
  end
end

【问题讨论】:

标签: ruby-on-rails ruby activerecord query-optimization


【解决方案1】:

我没有看到查询本身,所以我可能无法专门针对这种情况回答。

1。使用 Eager Loading 将 N+1 个查询转换为 1 个

一般来说,您的第一步应该是使用预先加载技术来防止 N+1 查询。您很可能正在请求尚未加载的关联集合(或单个对象)。

# controller
def index
  @customers = Customer.active
end

# view
<% @customers.each do |c| %>
  <%= c.name %> # this is fine the object is already in memory from your controller
  <%= c.address %> # this one makes a query to the database
<% end %>

这通常通过添加includes(association)来解决。

@customers = Customer.active.includes(:address)

2。确保您有关联外键的索引

另一个好东西是关联外键的索引。

add_index :customer, :address_id

在为某些复杂查询构建执行计划时,数据库引擎可能会选择不使用此索引,但对于简单的查询,情况就是这样。

3。使用子弹宝石

有一个坏蛋叫做bullet。它会在您开发应用程序时监视您的查询,并在您应该添加预加载(N+1 个查询)、何时使用不必要的预加载以及何时应该使用计数器缓存时通知您。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 2021-05-12
    相关资源
    最近更新 更多