Rails - 在多个关系中有效地提取和计算数据

时间:2010-11-24 16:53:54

标签: mysql ruby-on-rails performance

尝试使用Rails 2.3和MySQL以最有效的方式获取某些报告的数据。

我们的应用包含用户,优惠和已购买的广告。关系看起来像这样:

class User
  has_many :purchased_deals
  has_many :deals, :through => :purchased_deals
end

class Deal
  has_many :purchased_deals
  has_many :users, :through => :purchased_deals
end

class PurchasedDeal
  belongs_to :deal
  belongs_to :user
end

对于我正在运行的报告,我需要让所有已经购买的用户(即至少有一个已购买的DE),然后是他们已经购买的所有交易的总和(价格附在交易中) ,而不是PurchasedDeal)。

当然,我可以从所有用户的列表开始,包括交易和购买的交易。我已经尝试过,查询量很大(30,000个用户,提供或接受,3,000笔交易,100,000多笔购买交易)。

我可以从用户开始,然后做一个.each并找到已购买交易的那些,将它们分成他们自己的组,然后迭代每个那些以获得总数购买金额,但这是相当多的查询。

目前,这两种方法都需要很长时间才能超时。获得我需要的数据最有效的方法是什么?向表中添加列是完全可以接受的解决方案,顺便说一下。我有完整的数据库访问权限来完成我需要的工作。

谢谢!

2 个答案:

答案 0 :(得分:0)

假设您向purchase_deals表添加价格列,您可以获得用户信息和总交易价格,如下所示:

select users.id, sum(purchased_deals.price) from users, purchased_deals where users.id = purchased_deals.user_id group by users.id having sum(purchased_deals.price) > 0

答案 1 :(得分:0)

要获取具有多个购买的用户ID列表,您可以执行以下操作,这将只访问一个表:

user_ids = PurchasedDeal.count(:group => :user_id, :having => 'count_all > 0').keys

随后,您可以使用以下命令获取所有这些用户:

users = User.find user_ids

可以通过计数器缓存加快速度。在您的用户模型中,将选项:counter_cache => true添加到已购买交易的has_many关联中。您需要在users表上添加一个额外的整数列并进行初始化,在迁移中可能如下所示:

add_column :users, :purchased_deals_count, :integer, :null => false, :default => 0
User.each { |u| User.reset_counters u, :purchased_deals }

一旦这样做了,就会变得简单得多:

users = User.all :conditions => 'purchased_deals_count > 0'

Rails将使您的列保持最新状态,并进行大多数标准操作。


要获得总价格将始终涉及加入。或者你可以建立一个交易价格的哈希值,并在Ruby中进行繁琐的处理。我不是SQL专家,但您可以通过使用PurchasedDeal存储价格来摆脱加入。否则,以下是使用连接的方法:

user_id_to_price = PurchasedDeal.sum 'deal.price', :include => :deal, :group => :user_id

您可以通过添加:conditions => ['user_id IN (?)', users]之类的内容对您想要的用户进行过滤。 (其中users可以是ID列表,也可以是用户对象。)