【问题标题】:Rails fires N+1 queries for polymorphic associationsRails 为多态关联触发 N+1 个查询
【发布时间】:2017-07-20 07:47:18
【问题描述】:

我正在使用 Rails 5.0.1,并且对以下问题感到非常困惑。我很少有具有多态关联的模型。

class Container < ApplicationRecord
  has_many :steps, as: 'parent', dependent: :destroy
end

class Step < ApplicationRecord
  belongs_to :parent, polymorphic: true
  belongs_to :implementation, polymorphic: true
end

class FirstStep < ApplicationRecord
  has_one :step, as: 'implementation'
  has_many :params, dependent: :destroy
end

class SecondStep < ApplicationRecord
  has_one :step, as: 'implementation'
  has_many :headers, dependent: :destroy
end

class Param < ApplicationRecord
  belongs_to :first_step
end

class Header < ApplicationRecord
  belongs_to :second_step
end

步骤与实现相关联(FirstStepSecondStep)。除此之外,container 也可以是step 的实现。我正在使用Active Model Serializers 将模型信息序列化为 JSON。以下是序列化器的相关代码。

class StepSerializer < ActiveModel::Serializer
  attributes :id, :implementation_type, :implementation_id, :active, :position

  belongs_to :implementation
end

class FirstStepSerializer < ActiveModel::Serializer
  attributes :name, :params_attributes

  def params_attributes
    object.params.map { |p| ParamSerializer.new(p).attributes }
  end
end

class SecondStepSerializer < ActiveModel::Serializer
  attributes :id, :title, :headers_attributes

  def headers_attributes
    object.headers.map { |p| HeaderSerializer.new(p).attributes }
  end
end

class ParamSerializer < ActiveModel::Serializer
  attributes :id
end

class HeaderSerializer < ActiveModel::Serializer
  attributes :id
end

step 模型的实现可以具有不同的属性,如模型中所指定。问题是,当我写的时候

render json: container.steps

它会触发 N+1 个查询以获取结果。如何优化?

编辑 1

this answer 的启发,我尝试通过implementation_type 来分隔对象,并且成功了。我所做的是:

# my controller action
def index
  steps = []

  steps += container.steps.where(implementation_type: 'FirstStep').includes(implementation: [:params])
  steps += container.steps.where(implementation_type: 'SecondStep').includes(implementation: [:headers])

  render json: steps
end

这阻止了 N+1 个查询以获取 paramsheaders,但如果 stepcontainer,则它不起作用。

【问题讨论】:

    标签: ruby-on-rails polymorphic-associations active-model-serializers


    【解决方案1】:

    更改您的 FirstStepSerializerSecondStepSerializer 序列化程序,如下所示

    class FirstStepSerializer < ActiveModel::Serializer
      attributes :name
      has_many :params, :serializer => ParamSerializer
    end
    
    class SecondStepSerializer < ActiveModel::Serializer
      attributes :id, :title
      has_many :headers, :serializer => HeaderSerializer
    end
    

    这可能会有所帮助

    【讨论】:

    • 这仍然会触发 N+1 个查询,因为无法预先加载 object.implementationparamsheaders
    猜你喜欢
    • 2013-07-22
    • 2015-10-24
    • 2015-03-26
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多