为啥我的基于 postgis ST_Intersects 和 ST_Azimuth 的查询很慢?

Posted

技术标签:

【中文标题】为啥我的基于 postgis ST_Intersects 和 ST_Azimuth 的查询很慢?【英文标题】:Why my postgis ST_Intersects and ST_Azimuth based query is slow?为什么我的基于 postgis ST_Intersects 和 ST_Azimuth 的查询很慢? 【发布时间】:2019-07-29 14:57:35 【问题描述】:

我有一个表,其中包含大约 300k 条路线,起点、终点、路线为折线类型和多边形类型。

我做了一个自连接来找出路线的交叉点,但是查询很慢。即使我运行explain analyze,这个分析也没有回报。

CREATE INDEX gist_index_geo_poly_gon ON geo_akin USING gist (geo_polygon)
CREATE INDEX gist_index_geo_poly_line ON geo_akin USING gist (geo_polyline)
CREATE INDEX idx_id ON geo_akin USING btree (id)

我有上面的索引,查询如下:

 select 
 ST_Intersection(second.geo_polyline, first.geo_polygon)  as intersection,
from geo_akin first
   , geo_akin second
where second.id != first.id
  and abs(sin(ST_Azimuth(second.actual_start_point, second.actual_end_point))- sin(ST_Azimuth(first.actual_start_point, first.actual_end_point)))<1
  and abs(cos(ST_Azimuth(second.actual_start_point, second.actual_end_point))-cos(ST_Azimuth(first.actual_start_point, first.actual_end_point)))<1
  and st_intersects(second.geo_polyline , first.geo_polygon);

下面是我的EXPLAIN 结果:

   Nested Loop  (cost=0.15..45452.35 rows=128519 width=64)
  ->  Seq Scan on geo_akin found  (cost=0.00..2584.67 rows=3167 width=17077)
  ->  Index Scan using gist_index_geo_poly_line on geo_akin first  (cost=0.15..2.97 rows=1 width=4244)
        Index Cond: (geo_polyline && second.geo_polygon)
        Filter: ((id <> second.id) AND (abs((sin(st_azimuth(actual_start_point, actual_end_point)) - sin(st_azimuth(second.actual_start_point, second.actual_end_point)))) < '1'::double precision) AND (abs((cos(st_azimuth(actual_start_point, actual_end_point)) - cos(st_azimuth(second.actual_start_point, second.actual_end_point)))) < '1'::double precision) AND _st_intersects(geo_polyline, second.geo_polygon))

【问题讨论】:

@a_horse_with_no_name 我已经添加了解释结果。 性能问题应该包括EXPLAIN和一些关于表大小、索引、当前时间性能、期望时间等的信息。Slow是一个相对术语,我们需要一个真实的值来比较。 为什么会有折线和多边形?或许你可以使用second.id &gt; first.id来避免反向比较? 谢谢@JuanCarlosOropeza 我错过了这一点。现在我添加这个条件来避免反向比较。因为其中之一是线路(路线)的集合,而其中之一只是一个区域。我想找到路口。 你的查询有多慢?你能提供一些例子吗?我在路线和多边形方面做了很多工作,如果了解问题所在,我可能会给你更好的建议 【参考方案1】:

我可以看到,您对 300k 表的自联接为您提供了 90.000 万个交叉点。我的建议是尝试将连接过滤为仅重叠的多边形,然后查找它们是否相交。

如果为边界多边形添加 X1、Y1、X2、Y2 并使用 (ID, X1, Y1, X2, Y2) 创建索引,您可以非常快速地找到重叠的多边形

SELECT ST_Intersection(b.geo_polyline, a.geo_polygon) AS intersection
FROM geo_akin a
JOIN geo_akin b
  ON a.X1 <= b.X2
 AND a.X2 >= b.X1
 AND a.Y1 <= b.Y2
 AND a.Y2 >= b.Y1
 AND a.id < b.id
WHERE abs(sin(ST_Azimuth(b.actual_start_point, b.actual_end_point))
        - sin(ST_Azimuth(a.actual_start_point, a.actual_end_point))) < 1
  AND abs(cos(ST_Azimuth(b.actual_start_point, b.actual_end_point))
        - cos(ST_Azimuth(a.actual_start_point, a.actual_end_point))) < 1
  AND st_intersects(b.geo_polyline, a.geo_polygon);

【讨论】:

感谢回复,但是我们在where子句中已经有了st_intersects内置函数来查找是否有交集。您是否认为添加这些点并将它们作为条件会产生很大的不同? 是的,我想是的。如果不起作用,我们会尝试其他方法。

以上是关于为啥我的基于 postgis ST_Intersects 和 ST_Azimuth 的查询很慢?的主要内容,如果未能解决你的问题,请参考以下文章

基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用

postgis空间数据导入及可视化

PostgreSQL(PostGIS)安装和入门的若干问题

PostGIS常用的空间数据表的操作

关于postgis创建表指定geom类型的问题

关于postgis创建表指定geom类型的问题