这是我在使用 Rails 5 时面临的挑战(我使用 Skylight 报告 N+1 查询的服务,他们推荐的解决方案是 here ,但这对我来说还不够)。
我有一个表节点
,一个节点
可以有多个与之相关的节点
(有一列名为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
的 节点
不再有任何节点
。
问题是我面临 N+1 的性能问题,因为在原始查询中包含节点是不够的,因为在循环内我使用不同的范围查询每个记录。下面是暴露该问题的示例代码:
# 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
中条件的节点
.
有没有办法优化这个?
最佳答案
将 another_scope
替换为 select { |n| n.satisfies_another_scope_criteria? }
由于您已经获取了所有子级,因此无需再次在数据库中过滤它们,除非 another_scope
中有 limit
子句
关于ruby-on-rails - rails : Optimize query N+1 with same table one_to_many and scope conditions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46480973/