优化写连接表记录

时间:2015-08-21 09:23:09

标签: join activerecord ruby-on-rails-3.2 postgis rgeo

该应用程序基于PostGIS并使用RGeo的simple_mercator_factory存储数据。

创建多边形记录,并且与点的关联是静态的(即不需要更新)。为了减少postGIS计算的开销,有意义的是使用属于多边形的点填充连接表,并使用bTree(代替rTree)在索引连接表上搜索。

问题是有效创建连接记录。目前:

@line_string1 = RGeo::Geographic.simple_mercator_factory.line_string([@point_a, @point_b, @point_c, @point_d])
@points = Point.all
@points_in ||= []
@points.each do |point|
  this_point = point.lonlat
  @this_poly = RGeo::Geographic.simple_mercator_factory.polygon(@line_string1)
  if this_point.intersects?(@this_poly)
      @add_point = pointpolygon.new(:point_id => point.id, :polygon_id => @polygon.id)
      @add_point.save
  end
end

查询计划是可以接受的

EXPLAIN for: SELECT "point".* FROM "points"
                         QUERY PLAN
-------------------------------------------------------------
 Seq Scan on points  (cost=0.00..210.10 rows=8110 width=99)
(1 row)

但是,@add_point函数的时钟频率在14到16毫秒之间。对于一组83条记录,我们看起来像1.6秒。但总数匹配:
Completed 302 Found in 7796.9ms (ActiveRecord: 358.5ms)
在没有编写连接记录的情况下运行执行相同查询计划(和时间)的单独方法 Completed 200 OK in 1317.5ms (Views: 49.8ms | ActiveRecord: 64.0ms)
出现两个问题。更平凡的是,为什么总量会膨胀得那么多 - 除了开发模式条件之外我还期待3秒钟(1.6 + 1.3)?

但更重要的是,是否有办法以更有效的方式将连接表记录写入单独的线程(after_update?)(考虑可写入1000条记录......)

1 个答案:

答案 0 :(得分:0)

正如@Jakub正确指出的,一种方法是一次性提取所有有效点:

def valid_points
  Point.order("id").joins("INNER JOIN points ON points.id=#{id} AND st_contains(polygon.poly, points.lonlat)").all
end  

然后由控制器调用

  @valid_points = @polygon.valid_points
  @valid_points.each do |point|
    @add_point = Pointpolygon.new(:point_id => point.id, :polygon_id => @polygon.id)
    @add_point.save
  end

产生更好的响应时间。对于最多1000个匹配的测试用例,在开发模式下,每个记录创建的创建时间在1.2到1.4毫秒之间。