在某些情况下,当我获得 ActiveRecord Relation 时,我.each
在 ActiveRecord::Relation 上遇到了奇怪的行为
似乎是当 ActiveRecord::Relation 委托:each
给:to => :to_a
( source )
@tasks = Task.find_task(list, {:week_id => 1})
基本上,有一个冗长的类方法,它接受一个对象 (list
和一个带有 a 的哈希: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::Relation 上的可枚举问题。
更新
在算法内部(我认为这意味着类方法)我做了很多急切的加载。所以 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 ms
,139 ms
然后 - 一个包含大量 , 的大型 SQL 查询
LEFT OUTER JOINS in 33,000 ms
(很长,但不是大多数) 257,000 ms
在模板中。
to_a
当我在模板中复制行为时,我发现调用关系大约需要 3-4 分钟@tasks
。
所以,当我的服务器告诉我所有的时间都花在了模板上,并且我可以看到在关系上调用一个可枚举的东西时,那是在执行查询的时候吗?即使在top
我只能看到ruby
正在运行的进程?