2012-10-18 40 views
0

在某些情况下,当我得到一个ActiveRecord的关系,我在一个ActiveRecord遇到奇怪的行为与.each ::关系Rails的活动记录关系枚举

这似乎是在ActiveRecord的::关系代表:each:to => :to_asource

@tasks = Task.find_task(list, {:week_id => 1}) 

基本上,有一个长的类方法,它采用一个对象(list,并用:week_id散列)

过滤一束&查询发生这种find_task方法中,但它最终返回一个关系到@tasks

然后,在模板中,我有:

<% @tasks.each do |task| %> 
. 
. 
. 
<% end %> 

无论出于何种原因,无论是大小为@tasks,大约需要3分钟。我可以通过调用@tasks.to_a来复制相同的行为即使@tasks,ActiveRecord :: Relation的实例只有两条记录,在它们上调用to_a需要> 3分钟。

它不会发生在所有:week_id S,只能在特定的week_id,例如::week_id => 1

的SQL执行罚款,我得到一个关系回来,它只是似乎是一个枚举上一个问题特定的ActiveRecord ::关系。

更新

算法(我认为这意味着类方法),我做的预先加载的里面很多。所以Postgres做了很多LEFT OUTER JOIN s,我已经索引了所有需要发生的表。

一个解释分析显示,所有扫描都是index scans,事实证明,查询执行得很好,有很多急切的加载......并且我得到一个渴望加载的'ActiveRecord :: Relation'回到合理的数量时间。

更新2 虽然这个过程是服用3分钟,我看到了几秒钟一个Postgres处理运行,然后我看到这3分钟我的输出top

PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND                
8685 dylan  20 0 3407m 2.6g 904 R 99.7 69.1 1:14.49 /usr/local/bin/ruby script/rails s 

当它终于结束时,服务器显示这个;

  • 预先加载:200 ms139 ms然后
  • 大的SQL查询,有很多LEFT OUTER JOINS in 33,000 ms,(长,但不是其中大部分是),那么
  • 模板257,000 ms

当我复制模板的行为我看到它大约需要3-4分钟拨打to_a@tasks关系。

所以,当我的服务器告诉我所有的时间都花在模板上,而且我可以看到调用一个关于enumerable的关系需要永远的时间,是当查询被执行时?尽管在top我只能看到ruby进程正在运行?

回答

0

原来的问题是急于加载。当在ActiveRecord :: Relation实例上调用可枚举方法时,它将被委托给.to_a,而在Ruby中,.to_a方法可能需要很长时间才能处理大量关系。尽管我通过@tasks循环播放,但我仍然渴望加载如此多的对象,以至于.to_a花费的时间过长。

我的短期解决方案是简单地热切加载较少的对象。它最终以n + 1查询伤害了我,但我的.to_a方法不再疯狂。

这是我能想到的唯一解释。

0

我知道这是一个旧的帖子,但为了将来的参考,这将通过使用find_each来解决。

你可以在Ruby on Rails guides找到更多的信息。