在哪个点上最好是对大型项目进行所有查询以急切加载所有对象关联?
让我解释一下这个问题的背景
目前我正在开展一个在模型和协会方面变得相当复杂的项目。我开始检查服务器日志,并发现由于查询中包含嵌套对象,某些视图需要一些时间才能加载。
所以我开始将这些查询重构为以下内容:
@process = current_account.processes.query(params)
对此:
@process = current_account.processes.includes(:messages, :parts, :people).query(params)
结果非常好。在某些视图中,我能够将视图渲染时间和活动记录查询时间缩短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
然后继续
在我的show view
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)
那么,重构应用程序的设计以使这些关联行为不同是不会发生的,所以我再次提出问题。
在这一点上,对大型项目的所有查询都要急切加载所有对象关联是很好的吗?
欢迎任何有关该主题的提示/最佳实践/经验。
答案 0 :(得分:1)
“对大型项目的所有查询都急切加载所有对象关联” - 几乎从不。至少在没有应用程序内部帮助的情况下。
如果我在你的鞋子里,我会开始考虑缓存(你没有提到,所以我不知道你是否在做任何事情)。特别是片段缓存,因为它似乎很适合您的标签结构。
在一个应用程序中,我使用上下文相关的侧边栏显示项目组列表,每个组包含相关项目的链接(18个组中的任意一个项目中的n项),每个项目显示链接中相关项目的名称表单(以及其他一些小数据项)。
侧边栏中的每个组都被缓存,并且其组中的每个相关项目的条目也被缓存。控制器重构为将相关项目累积为@relateds,并且该代码利用高速缓存来确定是否需要获取(在高速缓存未命中时)。随着智能缓存过期的一点点工作,性能非常好。
假设项目X在12个类别(120个相关项目)中分别有10个相关项目。在Project X的第一个节目中,您需要付出代价。更改类别中1个相关项目的名称将使该项目的缓存,该项目的组以及整个侧边栏无效。在Project X的下一个节目中,侧边栏的重建涉及1个项目的1个缓存未命中(通过连接或两个读取该项目的记录),以便重建项目缓存,从10个项目缓存重建一个类别缓存(1新的+ 9现有的),缓存其他11个类别的命中(不读取这110个相关项目),并在最后产生重建的侧边栏缓存。
感觉你可以为你的标签采用类似的策略,甚至可能更精细,但这取决于你的实现。