0

特定のケースで、ActiveRecord Relation を取得すると.each、ActiveRecord::Relation で奇妙な動作が発生します。

ActiveRecord::Relationが( source )に委譲:eachするときのようです:to => :to_a

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

list基本的に、オブジェクト ( 、および を含むハッシュ:week_id)を取る長いクラス メソッドがあります。

このfind_taskメソッド内で一連のフィルタリングとクエリが発生しますが、最終的には次の関係を返します@tasks

次に、テンプレートには次のものがあります。

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

なんらかの理由で、 のサイズに関係なく、@tasks約 3 分かかります。ActiveRecord::Relation のインスタンスが 2 つのレコードしかない@tasks.to_a 場合でも、それらの呼び出しには 3 分以上かかります。@tasksto_a

すべての で発生するわけではなく:week_id、特定の week_id でのみ発生します。次に例を示します。:week_id => 1

SQL は正常に実行され、リレーションが返されます。これは、特定の ActiveRecord::Relation の列挙可能に問題があるようです。

アップデート

アルゴリズム (これはクラス メソッドを意味すると思います) の中で、大量の熱心な読み込みを行います。そのため、Postgres は多くのLEFT OUTER JOINs を実行し、これが必要なすべてのテーブルにインデックスを作成しました。

説明分析は、すべてのスキャンがそうであることを示して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テンプレートで。

to_aテンプレートで動作を複製すると、@tasks関係 を呼び出すのに約 3 ~ 4 分かかることがわかります。

それで、私のサーバーが私にそのすべての時間をテンプレートに費やされていることを教えてくれ、リレーションで列挙可能なものを呼び出すのが永遠にかかるのを見ることができるとき、それはクエリが実行されるときですか? topプロセスが実行されているのしか見えないのにruby

4

2 に答える 2

1

問題は熱心な読み込みにありました。ActiveRecord::Relation インスタンスで列挙可能なメソッドを呼び出すと、それは に委譲されます。これ.to_aには、膨大な数のリレーションのセットで非常に長い時間がかかる場合があります。をループしていたにもかかわらず@tasks、非常に多くのオブジェクトを熱心にロードしたため、.to_a時間がかかりすぎました。

私の短期的な修正は、n+1 クエリで私を傷つけることになるとしても、単純に少数のオブジェクトを熱心にロードすることです。

于 2012-10-19T05:03:40.717 に答える
1

これは古い投稿であることは知っていますが、今後の参考のために、find_each代わりに使用することで解決できます。

詳細については、Ruby on Rails ガイドを参照してください。

于 2015-01-26T19:42:14.677 に答える