为多对多关系有效循环和保存?

时间:2014-05-21 19:20:02

标签: ruby-on-rails ruby

我目前有这样的模型设置( - > =一对多):

Trader-> Service-> ServiceLocation< -Locations-> Trader(如果有意义的话)

交易者有一个原始位置,一个服务有一个范围,每次保存一个新服务我请求新服务对象调用一个实例方法.save_in_range!它接受trader_location,循环遍历数据库中的所有位置,并确定两者之间的距离,如果它在服务范围内,则保存ServiceLocations表中的关系:

class Service < ActiveRecord::Base
    belongs_to :trader
    has_many :service_locations
    has_many :locations, through: :service_locations

    def save_in_range!
        trader_origin = Trader.find(self.trader_id).location
      locations = Location.all

      locations.each do |location|
          if location.distance_from(trader_origin) <= self.range
            self.locations << location
          end
      end
    end
end

我的问题是,我真的需要以这种方式做到这一点还是我错过了一些OML魔术?如果不是这是一种有效的方式,还是我编写了糟糕的代码?

1 个答案:

答案 0 :(得分:0)

因此,使用您的估算数字,我们可以看到每次trader更改位置时,您都必须在所有locations上进行循环,这是一个大约1000的操作。我认为现在准备性能问题是值得的,因为这基本上意味着我们在trader.location相关操作的成本上有1000倍的乘数,并且这样做并不是那么困难。

我要做几个假设:

  • 每个location由两个坐标定义,x / y,长+纬度/球面角度,无论
  • 距离需要一些计算,例如2D中的斜边或地球上的haversine

我不会将所有位置加载到Ruby中,只是为了将少量location_ids保存回记录中。 相反,您应该按两个坐标索引每个位置,并计算SQL查询中的距离。

单独的SQL查询会产生很大的不同,但是您需要进一步优化:

  • 仅返回要在ruby中保存的SQL查询中的location_ids
  • 或根本不返回location_ids,只是直接在查询中更新service
  • 如果您的世界是地球仪,则将坐标存储为球面角度以节省计算
  • 在查询中的所有locations上运行距离计算之前,首先按边界矩形过滤(如果世界是2D,则为坐标矩形,如果在地球上,则为球面角矩形)

我还没有真正了解具体的实施细节,所以如果您在查找到目前为止我提到的不同组件的资源时请告诉我。