2010-11-24 25 views
1

尝试使用Rails 2.3和MySQL以最有效的方式获取某些报表的数据。Rails - 跨几个关系有效地提取和计算数据

我们的应用有用户,交易和购买交易。关系是这样的:

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 

对于我跑的报告,我需要的是已购买产品的所有用户(即至少有一个PurchasedDeal),然后总和所有的交易,他们已购买(价格附于交易,而不是购买交易)。

当然,我可以从所有用户的列表开始,包括交易和购买交易。我试过了,查询量很大(30,000个用户,有或没有,3000个交易,100,000个以上的购买交易)。

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

目前,这两种方法都需要很长时间才能使请求超时。获得我需要的数据最有效的方法是什么?向列添加列是一个完全可以接受的解决方案,顺便说一句。我有完整的数据库访问来做我需要的。

谢谢!

回答

0

要获得用户ID的列表与一个以上的购买,你可以做以下,这将只访问一个表:

users = User.find user_ids 

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

随后,您可以获取所有这些用户


事情可以加快与计数器缓存。在您的用户模型中,将:counter_cache => true选项添加到购买交易的has_many关联中。你会在你的用户表需要一个额外的整数列和初始化,这可能看起来在迁移如下:

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的列表,而且用户对象)。

+0

当我尝试运行您的第一条语句,它踢回MySQL错误关于“count_all”是一个未知的列。 – 2010-11-24 17:41:51

0

假设你添加的价格列purchased_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