Ruby on rails 子查询花费的时间太长,按进行排序

Ruby on rails 子查询花费的时间太长,按进行排序,ruby-on-rails,database,postgresql,optimization,Ruby On Rails,Database,Postgresql,Optimization,我正在尝试优化从此RoR代码呈现的查询: records.sort_by{r | r.badge_instances.count}.reverse.each do | s | 这将导致N+1个查询,因为对于每个记录,需要为排序获取一个计数 为了澄清,badge\u实例是记录的子对象。我可以使用什么rails方法来呈现一个查询,该查询获取所有badge实例计数,并保持与每个记录关联的计数进行排序 非常感谢你的帮助 您可以在获取记录时执行一次查询,然后使用size而不是count来防止N+1查询:

我正在尝试优化从此RoR代码呈现的查询:

records.sort_by{r | r.badge_instances.count}.reverse.each do | s |

这将导致N+1个查询,因为对于每个
记录
,需要为排序获取一个
计数

为了澄清,
badge\u实例
记录
的子对象。我可以使用什么rails方法来呈现一个查询,该查询获取所有badge实例计数,并保持与每个
记录关联的计数进行排序


非常感谢你的帮助

您可以在获取记录时执行一次查询,然后使用
size
而不是
count
来防止N+1查询:

records = Record.include(:badge_instances).where(...)

records.sort_by { |r| r.badge_instances.size }.reverse.each do |s|
  ...
end
在与@MrYoshiji进行对话时,如果这些表中的任何一个变得非常大,那么这可能会占用大量内存(因为这些对象的所有实例都将加载到内存中。在这种情况下,另一种方法是在查询中包含关联记录的计数作为属性:

records = Record.select("records.*, COUNT(badge_instances.id) as badge_instances_count").joins(:badge_instances).group("records.id")

然后,您可以访问每个
记录上名为
badge\u instances\u count
的属性,您可以使用该属性按计数大小对记录进行排序。请注意,
badge\u instances\u count
将是一个字符串,因此需要将其转换为整数,以便按实际计数进行排序。

我忘了提及我通过在BadgeInstance表的外键中添加索引对其进行了大量优化,但我确信,一旦数据变得足够大,就会再次出现问题。谢谢……这有点糟糕:实际上,您会将每个
badge\u实例
记录从DB转换到BadgeInstance的实例(ruby对象),然后您才可以计算数组的大小。在这种情况下,不需要将
badge_instance
记录作为Ruby Instanced对象,因为我们只想计算它们。我看不出这与您对OP问题的评论有什么不同。当运行应用程序时,它的工作原理与您在评论中建议的相同,正如您所说的r代码本质上与上面的代码相同,不是吗?我没有,在ActiveRecord::Relation对象上调用
.size
就像调用数组的
.size
.count
在ActiveRecord::Relation对象上实际上触发SQL计数。正确。因为
包含(:badge\u实例)
eager加载
BadgeInstance
对象及其相应的
记录
,调用
.size
将计算数组的大小,阻止N+1查询。正如您所说,如果我使用
.count
,将发生N+1查询。这是令人惊讶的正确,我现在感觉很糟糕:/感谢您的澄清和说明小森,@CDub!