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_node
的 node
不再具有 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
子句
这是我面临的一个挑战,使用 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_node
的 node
不再具有 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
子句