Ruby on rails 如何在联接后为返回的每个记录使用已加载的数据?
在我的代码中,我加入了两个模型(例如Post和Comment),然后我加载了第三个模型(例如Author)。当我打印每条记录时,rails对Post的第一个实例使用急切加载的模型数据,但对Post的每个额外实例触发额外的数据库查询。这是一个n+1问题 我不明白的是,为什么我只能对每个帖子的第一条记录使用急切加载的数据,而不能使用join返回的其他记录 我曾研究过类似的问题,但我觉得这些问题并不是针对同一个问题。这些措施包括:Ruby on rails 如何在联接后为返回的每个记录使用已加载的数据?,ruby-on-rails,eager-loading,Ruby On Rails,Eager Loading,在我的代码中,我加入了两个模型(例如Post和Comment),然后我加载了第三个模型(例如Author)。当我打印每条记录时,rails对Post的第一个实例使用急切加载的模型数据,但对Post的每个额外实例触发额外的数据库查询。这是一个n+1问题 我不明白的是,为什么我只能对每个帖子的第一条记录使用急切加载的数据,而不能使用join返回的其他记录 我曾研究过类似的问题,但我觉得这些问题并不是针对同一个问题。这些措施包括: ,及其他 我还特别研究了rails源代码,并尝试在本地对其进行
- ,及其他
find_by_sql
,并没有能够有效地实现这一点
我已经创建了一个我正在体验的和我正在获得的输出。任何帮助都将不胜感激
注意:这个示例是我能想到的最简单的设置,它演示了我在实际代码中遇到的相同问题。在我的示例中,我知道我可以急切地加载注释和作者,但是,在我的实际代码中有一个更复杂的连接,并且需要连接。我无法从这个示例中加载注释模型 对于那些在未来发现这一点的人,以下是我的发现和实施 简单的要点示例 对于我的要点中概述的简单示例,我发现我可以通过更改以下内容获得所需的结果 要点:
# Triggers n+1 for author after first puts of an author.
posts = Post.joins(:comments).select("posts.*, comments.body").includes(:author)
posts.each do |x|
puts "#{x.title} #{x.author.name} #{x.body}"
end
改为:
# Works as expected.
posts = Post.joins(:comments, :author).select("posts.*, comments.body").includes(:author)
posts.each do |x|
puts "#{x.title} #{x.author.name} #{x.body}"
end
通过加入作者
我不需要额外的查询就可以得到我想要的结果
更复杂的示例和实现
虽然上面解决了我用来演示问题的简单示例,但在我更复杂的实际问题中(如我的问题中所述),我无法实现这个额外的连接来解决问题
相反,我实现了查询对象模式和装饰器模式,如本文和github上的rails手册(和)中所述
这些模式允许我获得急切加载我想要的特定关联的所有好处,但对于我复杂得多的查询