当您只需要使用其中一个属性时,它是否优化内存以急切加载子对象?

时间:2017-03-15 23:30:15

标签: ruby-on-rails performance memory activerecord eager-loading

Order有多个孩子ItemsItems有许多孩子Charges。在def display类型的Controller方法及其关联视图中,我希望显示:1)order及其子items的所有属性和2){{的总和来自amount的1}}属性,用户友好的组合。如,

Charges

因为我以后需要所有<%= @order.id %> <%= @order.name %> <% @order.items.each do |item| %> <%= item.id %> <%= item.name %> <% end %> @total_item_charges # below 2 should sum into @total_item_charges above @total_item_type_a_charges @total_item_type_b_charges 属性,我想我知道要急切加载,但鉴于我只需要items的1个属性(和1来查询),我是否应该加载那呢?

接近A

使用charges急切加载孩子includes以及孙子items,以便所有信息都加载一次并根据需要使用

charges

方法B

仍然急切地加载孩子# CONTROLLER @order = Order.includes(items: [:charges]).where(id: params[:order_id]).first # items/charges already loaded into memory @order.items.each do |i| i.charges.each do |c| if c.type == "type_a" @total_item_type_a_charges += c.amount else @total_item_type_b_charges += c.amount end end end @total_item_charges = @total_item_type_a_charges + @total_item_type_b_charges ,而不是孙子items,而是在需要时进行charges次查询

where

在你的回答中......

  1. 如果我对所有事情都使用# CONTROLLER @order = Order.includes(:items).includes(:shipments).where(id: params[:order_id]).first @order.items.each do |i| @total_item_type_a_charges += i.charges.where(type:"type_a").pluck(:amount).inject(:+) @total_item_type_b_charges += i.charges.where(type:"type_b").pluck(:amount).inject(:+) end @total_item_charges = @total_item_type_a_charges + @total_item_type_b_charges 完全错误,那就完全标记(gulp,希望不是这样)
  2. 如果在内存使用和速度之间存在权衡(即,一种方法更快但使用更多内存,而另一种方法更慢但使用更少,请帮助我标记,因为这将有所帮助)
  3. 如果答案是好的,或者取决于细微的情况,那我可以问,因为我想知道这里是否有经验法则
  4. 很想知道如何在控制台中测试这个?我可以看到加载每个查询的毫秒数,但不是内存使用量

1 个答案:

答案 0 :(得分:0)

你必须考虑一个真实世界的情况,并且理想情况下,做一些性能测试。如果我要实现这一点,我会向total_charge添加Item字段,并在添加,更新或删除费用时保持更新,类似于belongs_to ... counter_cache: true

替代方案可能如下所示:

class Order < ActiveRecord::Base
  has_many :items # as before
  has_many :items_with_charge, :class_name: 'Item', 
           -> { joins(:charges).group('items.id').select('items.*, sum(charges.amount) as total_amount)') }
  ...
end

现在,如果您执行以下操作:

order = Order.includes(:items_with_charge)

每个项目都应包含使用item['total_amount']

访问的总数