自我引导关联:N + 1问题

时间:2014-10-26 17:29:51

标签: ruby-on-rails ruby-on-rails-4

假设我有以下型号:

class Strategy < ActiveRecord::Base
  belongs_to :user
  has_many :snapshots, :class_name => 'Strategy', :foreign_key => 'master_id'
  belongs_to :master, :class_name => 'Strategy', :counter_cache => :snapshots_count

  scope :master_only, -> { where(:master_id => nil) }
end

因此,任何用户都可以创建Strategy

的主 - 实例的快照

在控制器中我得到所有&#34;主人&#34;属于Strategy

current_user个实例
@strategies = current_user.strategies.master_only.includes(:user,:snapshots)

Rails在两个查询中正确加载strategiessnapshots,但在单独查询中为每个快照提取user,从而引入N + 1问题(在此特定情况下为N + 2):< / p>

Strategy Load (0.3ms)  SELECT `strategies`.* FROM `strategies` WHERE strategies`.`user_id` = 2 AND `strategies`.`master_id` IS NULL LIMIT 10 OFFSET 0   
User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IN (2)   
Strategy Load (0.8ms)  SELECT `strategies`.* FROM `strategies` WHERE `strategies`.`master_id` IN (56, 8, 55, 1, 58, 57, 24, 22)   
User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1   
....    
User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1

有没有办法更有效地加载快照用户?

1 个答案:

答案 0 :(得分:1)

您可以对:user:snapshots的加入方式略有改动,只生成一个查询来加载属于:snapshots的所有用户:

@strategies = current_user.strategies.master_only.includes(snapshots: :user)

生成的SQL查询类似于:

SELECT `strategies`.* FROM `strategies` WHERE strategies`.`user_id` = 2 AND `strategies`.`master_id` IS NULL LIMIT 10 OFFSET 0   
SELECT `users`.* FROM `users` WHERE `users`.`id` IN (2)   
SELECT `strategies`.* FROM `strategies` WHERE `strategies`.`master_id` IN (56, 8, 55, 1, 58, 57, 24, 22)
SELECT `users`.* FROM `users` WHERE `users`.`id` IN (2,5)

<强>更新

根据OP,以下解决了N + 1问题:

@strategies = current_user.strategies.master_only.includes(:user, snapshots: :user)