0

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

我有 5 个模型:

  • 赌注
  • 选择
  • 现货价格
  • 斑点区域
  • 产品

它们与以下内容相关:

  • 投注属于_to 选择
  • 选择belongs_to Spotarea
  • 选择belongs_to产品
  • 选择 has_many 投注
  • Spotprice 属于_to Spotarea
  • Spotprice 属于_to 产品
  • Spotarea has_many Spotprices
  • Spotarea has_many 选择
  • 产品有_many Sprotprices
  • 产品有_很多选择

我的目标是找到与特定投注匹配的 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

4 回答 4

1

在尝试减少查询数量之前,您应该在您的应用程序上运行性能测试,并监控数据库负载。有时最好运行几个小查询而不是一个包含几个连接的大查询。某些版本的 Oracle 似乎特别不擅​​长连接。

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

基本上:

  1. 你总是想避免 n+1 问题。
  2. 尝试将多个查询组合成一个连接在最好的情况下可能是过早的优化,而在最坏的情况下实际上会使性能变差。
于 2012-09-28T19:51:53.357 回答
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")
于 2012-09-28T18:59:37.773 回答
0

好吧,这是一个非常简单的更改:

b = Bet.includes(:choice).find(5).choice
于 2012-09-28T18:47:30.537 回答
0

After a few hours and a lot of Google search I found a solution that works.. After adding the join bridges I wanted to do:

Bet.find(5).spotprice

But that didn't work because to do that I needed something like this in my Choice model:

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

I that is not possible.. apperently..

So I found this link has_one :through => multiple and I could use that answer in my situation.

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

With the above I can now do:

Bet.find(5).choice.spotprice

If anybody got a better solution please let me know :)

于 2012-09-29T09:59:14.460 回答