假设我有以下型号:
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在两个查询中正确加载strategies
和snapshots
,但在单独查询中为每个快照提取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
有没有办法更有效地加载快照用户?
答案 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)