【问题标题】:Rails Eager Load and LimitRails 急切负载和限制
【发布时间】:2012-03-21 16:20:38
【问题描述】:

我认为我需要类似于 rails 急切加载的查询的东西,但我无法找到解决方案。

为了简单起见,假设系统中永远不会有超过 30 个Persons(所以Person.all 是一个小数据集)但每个人将有超过 2000 个 cmets(所以 @987654324 @ 将是一个大型数据集)。

家长协会

class Person < ActiveRecord::Base
  has_many :comments
end

儿童协会

class Comment < ActiveRecord::Base
  belongs_to :person
end

我需要查询Persons 的列表并包含他们的comments,但我只需要其中的 5 个。

我想做这样的事情:

有限的父关联

class Person < ActiveRecord::Base
  has_many :comments
  has_many :sample_of_comments, \
    :class_name => 'Comment', :limit => 5
end

控制器

class PersonController < ApplicationController
  def index
    @persons = Person.include(:sample_of_comments)
  end
end

不幸的是,this article 声明:“如果您使用指定的 :limit 选项急切加载关联,它将被忽略,并返回所有关联的对象”

有什么好的办法吗?还是我注定要在急切加载 1000 个不需要的 ActiveRecord 对象和 N+1 查询之间做出选择?另请注意,这是一个简化的示例。在现实世界中,我将与Person 有其他关联,在与comments 相同的问题的相同index 操作中。 (照片、文章等)。

【问题讨论】:

  • 不管是 rails 还是 activerecord,首先尝试提出您认为可以为您提供结果集的 SQL 对。如果你不能,那么任何 orm 库也不能。
  • @ChadM 你有没有设法解决这个问题?还是您有一些一般性建议可以为某人指明正确的方向?我也有同样的问题:我不想急切加载 2000 cmets :'(
  • @BKSpureon 不幸的是,我们没有。事实证明,我们的 Persons 集合(根据上面的示例)每页将足够小,以至于 N+1 查询是两个弊端中较小的一个。如果不是这样,我们可能会做一个类似于接受的答案的after_commit,或者将某种触发器直接放入数据库中做同样的事情。

标签: ruby-on-rails limit eager-loading


【解决方案1】:

不管“那篇文章”怎么说,问题在于 SQL 中,您无法在这种情况下完全使用标准 LIMIT 来缩小第二个 sql 查询(急切加载)的范围。

但是,您可以添加一个新列并改为执行 WHERE 子句

  1. 将您的第二个关联更改为Person has_many :sample_of_comments, conditions: { is_sample: true }
  2. is_sample 列添加到comments
  3. 添加一个分配is_sample = person.sample_of_comments.count &lt; 5Comment#before_create 挂钩

【讨论】:

  • 嗨 choonkeet,这不是一个坏主意。不幸的是,对于该人创建的每条评论,将被视为样本的 cmets 集将移动一个。我想对所有语句集进行某种更新都可以解决这个问题,但这似乎是一个沉重的写作。示例:Person 有 5 个 cmets,都是“样本”。人创建了第 6 条评论。现在,注释 1 应该不再是样本集的一部分,而 2 到 6 现在是样本 cmets 集。
猜你喜欢
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多