简化Rails查询

时间:2012-09-28 18:24:02

标签: ruby-on-rails activerecord associations

我正在尝试减少应用程序中的查询数量,并需要以下设置方面的帮助:

我有5个型号:

  • 赌注
  • 选择
  • Spotprice
  • Spotarea
  • 产品

它们与以下内容相关联:

  • Bet belongs_to Choice
  • Choice belongs_to Spotarea
  • 选择belongs_to产品
  • 选择has_many Bets
  • Spotprice belongs_to Spotarea
  • Spotprice belongs_to产品
  • Spotarea has_many Spotprices
  • Spotarea has_many Choices
  • 产品has_many Sprotprices
  • 产品has_many选择

我的目标是找到与特定投注匹配的Spotprices。要做到这一点,我使用以下查询,但我确信它可以以更好的方式完成,所以当我进行100次投注并想要查看它们是否高于或低于相应的Spotprice我不会超载数据库查询。

a = Bet.find(5)

b = Choice.find(a.choice_id)

c = Spotprice.where(:spotarea_id => b.spotarea_id, :product_id => b.product_id, 
    :deliverydate => b.deliverydate).first

谢谢!

4 个答案:

答案 0 :(得分:1)

首先,设置连接桥:

class Choice
  has_many :spotprices, :through => :spotarea
end

class Bet
  has_many :spotprices, :through => :choice
end

然后你可以查询像

这样的东西
Bet.joins(:spotprices).where("spotprices.price > bets.value")

答案 1 :(得分:1)

在尝试减少查询数量之前,您应该对应用程序运行性能测试,并监视数据库负载。有时最好运行一些小查询而不是一个带有少量连接的大查询。某些版本的Oracle在加入时似乎特别糟糕。

联接的替代方法,如果您尝试避免n + 1查询问题,则使用preload并传递关联(preload采用与includes相同的参数)。这使得ActiveRecord每个表运行一个查询。

基本上:

  1. 你总是想避免n + 1问题。
  2. 尝试将多个查询组合到一个连接中可能在最好的情况下是过早的优化,而在最坏的情况下实际上会使性能变差。

答案 2 :(得分:0)

这是一个非常简单的改变:

b = Bet.includes(:choice).find(5).choice

答案 3 :(得分:0)

经过几个小时和大量的Google搜索后,我找到了一个有效的解决方案..添加了我想要的连接桥后:

Bet.find(5).spotprice

但这不起作用,因为要做到这一点,我在我的Choice模型中需要这样的东西:

has_one :spotprice, :through => [:spotarea, :product] :source => :spotprices

我不可能......显然......

所以我找到了这个链接has_one :through => multiple,我可以在我的情况下使用这个答案。

class Choice < ActiveRecord::Base
  belongs_to :user
  belongs_to :spotarea
  belongs_to :product
  has_many   :bets

  def spotprice
    Spotprice.where(:product_id => self.product_id, :spotarea_id => self.spotarea_id, :deliverydate => self.deliverydate).first
  end

class Bet < ActiveRecord::Base
  belongs_to :user
  belongs_to :choice
  has_one    :spotprice, :through => :choice

通过上述我现在可以做到:

Bet.find(5).choice.spotprice

如果有人有更好的解决方案,请告诉我们:)