1

我有一个向用户显示的提要,其中包括 4 种不同的模型类型。

它通过将一天对象插入到提要中来模拟按天对条目进行分组。

提要按时间顺序排序和分页。

这就是我目前构建提要的方式。

def get_feed initial_feed_position=0, number_of_entries_to_get=30
  # display is called on each model to get them all into a standard format
  feed = (first_models + second_models + third_models + forth_models).map { |feed_entry| feed_entry.display }
  feed += day_entries_for_feed(feed)
  end_feed_position = initial_feed_position + number_of_entries_to_get
  (feed.sort_by { |feed_entry| -feed_entry[:comparison_time].to_i })[initial_feed_position...end_feed_position]
end

def day_entries_for_feed feed
  # iterate over a set of dates that contain feed entries
  feed.map{ |feed_entry| feed_entry[:date] }.uniq.map do |day|
    # building the day object in the standard feed entry format. fields that are not relevant to this question have been left out.
    {
      type: 'day',
      comparison_time: (day + 24.hours - 1.second).time # to ensure that the day appears above it's corresponding entries in the feed, the comparison time is set to 1 second before the day ends
    }
  end
end

随着时间的推移,系统中的对象数量已经增加,现在使用这种方法构建提要需要很长时间。有更好的方法吗?

我正在使用 Rails 3.2.13、Ruby 1.9.3 和 PostgreSQL 9.1.9。

4

2 回答 2

4

因为您要获取数据库中的所有条目,所以很多模型都加载到内存中,要解决这个问题,您必须查看 UNION(这很难维护,并且您的代码库中必须有文字 SQL )。一个很好的例子在这里:PosgreSQL: How to union 3 tables sorted by date

另一种选择是派生一个基类并对此进行查询。这将导致这样的事情:

                              +-------------+
                              |  BASE FEED  |
                              |             |
                              +------^------+
                                     |
        +-------------------+--------+---------+----------------+
        |                   |                  |                |
  +-----+-------+    +------+------+   +-------+-----+   +------+-----+
  |  MODEL ONE  |    |  MODEL TWO  |   | MODEL THREE |   | MODEL FOUR |
  |             |    |             |   |             |   |            |
  +-------------+    +-------------+   +-------------+   +------------+

一旦你像这样设置了模型,查询这个基表就很简单了。这可能看起来像这样:

def get_feed(initial_feed_position = 0, number_of_entries_to_get = 30)
  feeds = BaseFeed.
    limit(number_of_entries_to_get).
    offset(initial_feed_position).
    order("DATE(date_field) DESC")
end

上面的示例不是确切的解决方案,但如果您详细说明您想要获得的结果集,我可以对其进行调整,但更多的是关于采取的方法。

希望这可以帮助。

于 2013-05-05T14:25:47.020 回答
3

不更改数据库的解决方案:

您的代码变慢的原因是您查询了所有对象,然后只取前 30 个(number_of_entries_to_get)

因为它是一个提要,我们可以假设大多数时候,用户会查看前几页。

您可以直接从数据库中获取最新的 end_feed_position(按日期排序),而不是获取所有 first_models/second_models 等

就像是:

models = FirstModel.order("date DESC").limit(end_feed_position)
models += SecondModel.order("created_at DESC").limit(end_feed_position)

因此,例如,如果您在第 2 页上并搜索 30 的提要:

您只从数据库中查询 240 个对象 (first_models + second_models + third_models + Fourth_models) * 60 并且这 240 个中的 30..60 是所有对象中的 30..60 (因此它不会像数据库一样变慢在成长)

于 2013-05-07T09:06:44.123 回答