MongoMapper 避免在 Rails 上的 Ruby 中引起 N+1 查询

MongoMapper Avoiding causing N+1 queries in Ruby on Rails

所以我有两个 Class 看起来像这样

class Branch
  include MongoMapper::Document

  many :builds
end

class Build
  include MongoMapper::Document

  belongs_to :branch
end

并且如果我们想从 Build Class 访问 Branch 数据。我可以像下面那样做

builds = Build.where(___)

builds.each do |build|
  puts "#{build.branch.name} build number #{build.number}"
end

但这会触发导致 N+1 查询的警报,因为它进行了太多独立的数据库查询。好吧,解决方案是使用如下所示的 Eager Load

builds = Build.where(____).includes(:branches)

builds.each do |build|
  puts "#{build.branch.name} build number #{build.number}"
end

好吧,正如我从他们的文档中看到的那样,预加载或 .includes() 在 MongoMapper 中不可用(我希望我错了)。但它在 MongoId 中可用。但是,我暂时不打算从 MongoMapper 更改为 MongoId。你知道这件事的转机吗?这也许可以减少查询。

根据 docs Mongoid 的 #includes...将根据对 id 的额外查询将所有文档加载到 id 匹配的身份映射中。"

所以根本没有什么魔法——听起来它只是执行了一个额外的查询来获取关联的实体并将它们保存在内存中的某种数据结构中,读取时间复杂度为 O(1)([=24 中的哈希=],例如)。你可以自己做(免责声明:有点伪代码即将到来,作为参考,不是现成的解决方案):

builds = #...
branches = Branch.where(id: builds.map(&:id)).to_h { |br| [br.id, br] }

builds.each do |build|
  puts "#{branches[build.branch_id]&.name} build number #{build.number}"
end

但请注意:如果您必须经常进行这种记忆,这可能表明数据模型不是 document-based 数据库的最佳选择 - 嵌入式文档可能是更有效的解决方案。 .