首页 文章

简化Rails查询

提问于
浏览
0

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

我有5个型号:

  • 投注

  • 选择

  • Spotprice

  • Spotarea

  • 产品

它们与以下内容相关联:

  • Bet belongs_to Choice

  • Choice belongs_to Spotarea

  • 选择belongs_to产品

  • 选择has_many投注

  • Spotprice belongs_to Spotarea

  • Spotprice belongs_to产品

  • Spotarea has_many Spotprices

  • Spotarea has_many选择

  • 产品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

    首先,设置连接桥:

    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

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

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

    基本上:

    • 你总是想避免n 1问题 .

    • 尝试将多个查询组合成一个连接可能在最好的情况下是过早优化,而在最坏的情况下实际上会使性能变差 .

  • 1

    那么这是一个非常简单的变化:

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

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

    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
    

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

相关问题