Rails: 使用相同的 table one_to_many 和范围条件优化查询 N+1

Rails: Optimize query N+1 with same table one_to_many and scope conditions

这是我面临的一个挑战,使用 Rails 5(我使用 Skylight service that reports N+1 queries, and their recommended solution is here,但在我的情况下这还不够)。

我有一个 table nodes 和一个 Node 可以有多个 nodes 与之相关(有一个名为 parent_node_id 的列)给出我能够将一对多.

联系起来
class Node < ApplicationRecord
  ...
  belongs_to :parent_node, foreign_key: :parent_node_id, class_name: 'Node', optional: true, inverse_of: :nodes
  has_many :nodes, foreign_key: :parent_node_id, class_name: 'Node'
  ...
end

重要 层次结构的级别最大为 1。这意味着 node.nodes.first.node 不会发生。具有 parent_nodenode 不再具有 nodes.

问题是我面临 N+1 的性能问题,因为在原始查询中包含 nodes 是不够的,因为在循环中我查询具有不同范围的每条记录。这是暴露问题的示例代码:

# In a controller, including nodes so it does not query inside
nds = Node.some_scope.include(:nodes)
nds.each do |nd|
  ...
  # In a model
  # If I loop inside, there's no extra SQL queries, all good
  nd.nodes.each do |nd2|
    ...
  end
  ...
  # In a model
  # Here's the N+1 issue
  nd.nodes.another_scope.each do |nd3|
    ...
  end
  # Returns a value to the controller
  ...
end

无论如何都会触发每个 nd3 变量的 SQL 查询,因为有 another_scope 修改了原始的 nds 值,我不能将条件包含在nds 值,因为 nd2.

需要 another_scope 中不符合条件的 nodes

有没有办法优化这个?

another_scope替换为select { |n| n.satisfies_another_scope_criteria? }

由于您已经获取了所有子项,因此无需在数据库中再次过滤它们,除非 another_scope

中有 limit 子句