0

在 PHP(过去)中,您曾经mysql_fetch_assoc在 html 上逐行打印一些内容。基本上,你正在对一些 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')

如果我需要,我可以选择添加其他条件,例如,为特定组织旅行。

注意如果可能的话,我想避免分页。

我的想法:在我的想象中,这应该像“光标”一样工作,我进行查询,而不是存储类似的东西@trips_cursor = myquery,然后在视图trips_cursor.each_row do |trip|中创建一个模型对象(并丢弃它)每次都需要循环。它显然可以是只读的。

我需要 ruby​​ on rails 代码,而不是 PHP

更新答案

由于我同时学到了一些东西,所以我想分享一些我发现的信息。首先,如果您使用 AR 查询(where、joins、limit 和一些类似的方法),查询将不会运行(延迟加载),直到您在查询上运行一个方法,这不是AR 方法。基本上每个each方法都会触发查询。因此,如果您find_each(batch_size: 1)在未触发的 AR 查询上执行 ,它只会在内存中加载一行并每次打印出来,从而保留您宝贵的 RAM。请注意,我使用这种方法只是因为,由于我的巨型连接,我加载了所需的所有内容并且所有记录都是唯一的,因此我不需要缓存它们。

4

3 回答 3

1

检查此链接:

http://guides.rubyonrails.org/active_record_querying.html#retrieving-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 回答