0

PHP(昔)mysql_fetch_assocでは、HTMLに行ごとに何かを印刷していました。基本的に、touは、結果全体をメモリに保存せずに、いくつかのSQL結果をループしていました。

非常に大きなクエリを作成しているときに、必要なすべてのテーブルを「結合」して大きな行を作成する状況があります。たとえば、関連するモデルをリクエストすると、データが考慮されるため、クエリはデータベースを呼び出しません。 「キャッシュ」。

このクエリの最大の問題は、それが巨大で、多くのものをメモリにロードすることです。は結合で構築されているため、使用されているすべてのテーブルのすべてのデータを一度にメモリにロードする必要はありません。すべての行が直接印刷可能であるため(この結合のおかげで)、基本的に、フェッチされた各行でループを作成することを考えました。直接印刷してから破棄します。

どうすればそのようなことを達成できますか?

これは私が使用している大まかなテーブル構造です(完成していません):

Trips
  - has_many Hikers
  - belongs_to Organization

Hikers
  - belongs_to PersonalRecord

PersonalRecord

Organization
  - has_many Trips

私の参加は、単にすべての旅行に参加し、このテーブルのすべての行を組織、ハイカー、個人の記録に参加させます。

アップデート1:

現在、このクエリを使用して結果を取得しています。

table_join_to_cache = '
  INNER JOIN organizations    ON organizations.id         = trips.organization_id
   LEFT JOIN cities           ON cities.id                = trips.city_id
   LEFT JOIN hiker_trips      ON hiker_trips.trip_id      = trips.id
   LEFT JOIN hikers           ON hikers.id                = hiker_trips.hiker_id
   LEFT JOIN personal_records ON personal_records.id      = hikers.personal_record_id
   LEFT JOIN trip_trip_levels ON trip_trip_levels.trip_id = trips.id
   LEFT JOIN trip_levels      ON trip_levels.id           = trip_trip_levels.trip_level_id
'
@trips = Trip.joins(table_join_to_cache)
             .where('trips.begin_date >= ? AND trips.begin_date <= ?', begin_of_month, end_of_month)
             .uniq.order('begin_date ASC, title ASC')

また、特定の組織への出張などが必要な場合は、オプションで他の条件を追加します。

NB私は可能であればページネーションを避けたいと思います。

私の考え:私の想像では、これは「カーソル」のように機能するはずです。次のようなものを格納するのではなく、クエリを作成します。ループで必要になるたびに@trips_cursor = myquery、ビューでモデルオブジェクトが作成されます(破棄されます)。trips_cursor.each_row do |trip|明らかに読み取り専用にすることができます。

PHPではなくRubyonRailsコードが必要です

回答の更新

その間に何かを学んだので、見つけた情報を共有したいと思います。まず、ARクエリ(ここで、結合、制限、およびいくつかの同様のメソッド)を使用する場合、 ARメソッドではないクエリでメソッドを実行するまで、クエリは実行されません(遅延読み込み) 。基本的に、すべてのメソッドがクエリを実行します。そのため、実行されていないARクエリでを実行すると、メモリ内の1つの行のみが読み込まれ、毎回それが出力され、貴重なRAMが保持されます。このアプローチを使用したのは、巨大な結合のおかげで、必要なものがすべて読み込まれ、すべてのレコードが一意であるため、キャッシュする必要がないためです。eachfind_each(batch_size: 1)

4

3 に答える 3

1

このリンクをチェックしてください:

http://guides.rubyonrails.org/active_record_querying.html#retrieveing-multiple-objects-in-batches

あなたが求めているのはfind_each方法だと思います。デフォルトでは、一度に1000行をロードすることになっていますが、これはおそらく問題ありませんが、フェッチする行数を増減するように構成できます。

それがお役に立てば幸いです。

于 2013-01-25T17:59:30.160 に答える
1

@tripsがビュー内のリレーションである場合、find_eachまたはfind_in_batchesを使用する例(より良い場合があります):

<%= @trips.find_in_batches do |trips| %>
  <%= render partial: trips %>
<% end %>

どのようだ?

また、結果が非​​常に大きい場合は、ActiveSupport :: Cache :: Store:http://guides.rubyonrails.org/caching_with_rails.html#activesupport-cache-storeなどのキャッシュの形式を使用することを検討することを強くお勧めします

于 2013-01-25T18:25:21.363 に答える
0

賢い解決策はたくさんあると思いますが、SQLクエリで古き良きLIMITを使用しないのはなぜですか?500行をフェッチするだけで、それらを処理してさらに多くの行を処理できます。

于 2013-01-25T18:00:57.150 に答える