【问题标题】:Simplify Rails Query简化 Rails 查询
【发布时间】:2012-09-20 15:42:39
【问题描述】:

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

我有 5 个模型:

  • 下注
  • 选择
  • 现货价格
  • Spotarea
  • 产品

它们与以下内容相关联:

  • Bet belongs_to Choice
  • Choice belongs_to Spotarea
  • 选择属于_产品
  • Choice has_many Bets
  • Spotprice 属于_to Spotarea
  • Spotprice 属于_to 产品
  • Spotarea has_many Spotprices
  • Spotarea has_many Choices
  • 产品有_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

谢谢!

【问题讨论】:

    标签: ruby-on-rails activerecord associations


    【解决方案1】:

    这里有一个非常简单的改变:

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

    【讨论】:

    • :includes 执行单独的查询并加入 ruby​​。使用 :joins 进行真正的连接
    • 这并不完全正确。它有时会执行额外的查询,有时不会。
    【解决方案2】:

    首先,设置连接桥:

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

    然后你可以查询类似的东西

    Bet.joins(:spotprices).where("spotprices.price > bets.value")
    

    【讨论】:

    • 谢谢.. 连接桥确实有帮助,但仍然没有完全解决问题.. 我已经发布了解决方案的答案.. 感谢您帮助引导我朝着正确的方向前进..
    【解决方案3】:

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

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

    基本上:

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

    【讨论】:

    • 感谢您的出色回答.. 我肯定会调查 preload 的事情并尽量避免 n+1 问题.. 我必须查找因为我没有知道你在说什么:)
    【解决方案4】:

    经过几个小时和大量的 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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-16
      • 2022-01-08
      • 2014-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多