【问题标题】:MongoMapper Avoiding causing N+1 queries in Ruby on RailsMongoMapper 避免在 Ruby on Rails 中导致 N+1 查询
【发布时间】:2021-02-17 23:24:01
【问题描述】:

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

class Branch
  include MongoMapper::Document

  many :builds
end

class Build
  include MongoMapper::Document

  belongs_to :branch
end

如果我们想从Build 类访问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

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

【问题讨论】:

    标签: ruby-on-rails ruby mongodb eager-loading mongomapper


    【解决方案1】:

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

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

    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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 2016-09-13
      • 2022-01-13
      相关资源
      最近更新 更多