2

在什么时候对大型项目进行所有查询以预先加载所有对象关联比较好?
让我解释一下这个问题的背景。
目前我正在研究一个在模型和关联方面变得相当复杂的项目。我开始检查服务器日志,发现由于查询中包含嵌套对象,一些视图需要一些时间才能加载。
所以我开始将其中一些查询重构为如下所示:

@process = current_account.processes.query(params)

对此:

@process = current_account.processes.includes(:messages, :parts, :people).query(params)

结果还不错。在某些视图中,我能够将视图渲染时间和 activerecord 查询时间减少 70%。
伙计,我很高兴,所以我决定做更多。但是在做出这个决定之后,我开始注意到并非所有我都重构了代码的地方,变化都很好。事实上,有些查询变得更慢了。
为了更多地解释这个问题,我有一个这样的模型:

class Process
  has_many :anotations
  has_many :publications
  has_many :movimentations
  has_many :reunions
  has_many :profiles
  ...

里面的每一个嵌套模型process belongs_to :user都是这样创建的:

class Anotation
  belongs_to :user

class Reunion
  belongs_to :user

class Profile
  belongs_to :user

它继续。
在 my show viewof 中process,有几个选项卡显示所有这些嵌套对象以及将其添加到当前进程的用户的名称。
使用这样的查询:

@process = current_account.processes.query(params)

它的表现有点慢。所以我尝试了这样的事情:

@process = current_account.process.includes(:anotations, :publications, :movimentations, 
  :reunions, :profiles, :messages).query(params)

这使我加快了视图渲染的速度,但在 activerecord 中,检索这些对象的时间显着增加。user当我急切地将对象加载到所有嵌套模型中时,它升到了天空process

@process = current_account.process.includes({:anotations => [:user]}, 
  {:publications => [:user], etc...).query(params)

好吧,重构应用程序的设计以使这些关联表现出不同的行为是不会发生的,所以我再次问这个问题。
在什么时候对大型项目进行所有查询以预先加载所有对象关联比较好?
任何有关该主题的提示/最佳实践/经验将不胜感激。

4

1 回答 1

1

“对大型项目的所有查询都渴望加载所有对象关联” - 几乎从不。至少在应用程序内部并非没有帮助。

如果我站在你的立场上,我会开始研究缓存(你没有提到,所以我不知道你是否在做任何事情)。尤其是片段缓存,因为它似乎很适合您的选项卡结构。

在一个应用程序中,我使用上下文相关的侧边栏显示项目组列表,每个组包含指向相关项目的链接(18 个组中的任何一个项目),每个项目以链接形式显示相关项目的名称(和其他几个小数据项)。

侧边栏中的每个组都被缓存,并且其组中每个相关项目的条目也被缓存。控制器重构以将相关项累积为@relateds,并且该代码使用缓存来确定是否需要获取(在缓存未命中时)。在智能缓存过期方面做了一些工作,性能非常好。

假设项目 X 在 12 个类别中的每个类别中有 10 个相关项目(120 个相关项目)。在 Project X 的第一场演出中,你付出了代价。更改类别中 1 个相关项目的名称将使该项目的缓存、该项目的组和整个侧边栏无效。在 Project X 的下一个节目中,侧边栏的重建涉及 1 个项目的 1 个缓存未命中(通过一两个连接读取该项目的记录),因此项目缓存得到重建,一个类别缓存从 10 个项目缓存重建(1新的 + 9 个现有的),其他 11 个类别的缓存命中(不读取这 110 个相关项目),并在最后产生了一个重建的侧边栏缓存。

感觉您可以为您的选项卡采用类似的策略,甚至可能更细粒度,但这取决于您的实施。

于 2012-07-30T16:49:18.970 回答