最小化对rails中数据库的调用

时间:2010-05-22 17:04:07

标签: ruby-on-rails ruby performance memcached

我熟悉memcached和eager loading,但似乎都没有解决我面临的问题。

我的主要性能滞后来自数据库的数百个数据检索调用。棘手的是,在我有几个计算步骤之前,我不知道需要检索哪组用户。

我可以重构我的代码,但我想知道你的专家如何处理这种情况?我认为这应该是一个相当普遍的情况

def newsfeed

  - find out which users i need
  - retrieve those users via DB

  - find out which events happened for these users
  - for each of those events
        - retrieve new set of users

  - find out which groups are relevant
  - for each of those groups
        - retrieve new set of users 

  - etc, etc 

end

4 个答案:

答案 0 :(得分:2)

非规范化是您情况的神奇密码。

有几种方法可以做到这一点: 例如,将最后10个用户的ID存储在事件和组中。

或创建新模型NewsFeedItem (belongs_to :parent, :polymorphic => true)。当用户参加活动时,创建一个具有非规范化信息的NewsFeedItem,例如此用户名,他的个人资料图片等。将您从第二个查询保存到user_events和用户。

答案 1 :(得分:1)

您应该可以使用每个事件/组循环只有一个查询来执行此操作。您要做的是:在for循环中将用户ID添加到Set ,然后在 for循环后,检索具有这些ID的所有用户记录。冲洗并重复。这是一个例子:

def newsfeed

  user_ids = Set.new
  # find out which users i need
  ...  add ids to user_ids
  # retrieve those users via DB
  users = User.find(user_ids.to_a)

  # find out which events happened for these users
  # you might want to add a condition
  # that limits then events returned to only recent ones
  events = Event.find_by_user_id(user_ids.to_a)

  user_ids = Set.new
  events.each do |event|
    user_ids << discover_user_ids_for_event(event)

  # retrieve new set of users
  users = User.find(user_ids.to_a)

  # ... and so on  

end

我不确定您的方法应该返回什么,但您可以通过使用ID集合来找出如何使用finds分组在一起的想法,以尽量减少数据库查询。

答案 2 :(得分:1)

你想一次显示所有细节吗(我的意思是当页面加载时你真的想加载所有这些信息),如果不是你可以做的是,按需加载它们

如下

def newsfeed

  • 找出我需要的用户
  • 通过DB检索这些用户

  • 找出这些用户发生了哪些事件

    一旦你显示事件给他们一个按钮或者其他东西可以深入到其他细节(在-demand上)然后使用AJAX加载它们(这样页面就不会刷新)

    当用户想深入了解详情时,请反复使用此技术

通过这样做,您将节省大量处理能力,并且只能获得用户需要的详细信息

我不知道这是否适用于您的情况

如果没有,那么你必须找到一种更加优化的加载细节的方法

欢呼声, sameera

答案 3 :(得分:1)

据我所知,您正在尝试根据您的数据执行某种算法,以执行某种推荐或类似的操作。

我有两点建议:

1)您根据实际想要实现的目标重新评估算法/设计。例如,在应用程序具有可能具有大量帖子并且应用程序想要基于帖子数量执行某些算法的用户的情况下,每次计数他们的帖子将是非常昂贵的。为了优化这一点,可以在用户模型上添加post_count列,并在用户成功发布帖子时增加该计数。同样,如果您可以在用户,事件,组等之间建立某种类似的关系,那么请考虑这些问题。

2)如果第一个解决方案不可行,那么对于这样的任何事情,你必须避免做多个查询,然后使用ruby来处理数据,这显然是非常昂贵的,如果你有大数据集,这是绝对不可取的。所以你需要的是使用join创建一个sql查询并一次性获取所有数据。还只从数据库中选择您需要的那些字段名称。对于大型数据集,它确实很有用。例如,如果您需要来自用户和事件表的用户ID和event_id而不需要其他内容,那么请执行类似的操作

User.find(:all, 
      :select => 'users.id, users.event_id', 
      :joins => 'join events on users.id = events.user_id',
      :conditions => ['users.id in (your user ids)'])

我希望这会指出你正确的方向。