如何解决PostGIS ST_Intersects中的性能问题?


9

我是Postgis的新手,查询性能有问题。

这是我的查询:

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes here',4326),position) 
ORDER BY userid, timestamp desc

问题是我的multipolygon包含非常大的多边形(word文档中有600页长!),执行时间超过2个小时!

有没有一种方法可以优化我的查询或使用另一种方法?

请您的帮助,万分感谢!

Answers:


8

您应该做的是将大型多面体作为单个面(使用ST_Dump)放入表中,并在其上放置索引。就像是:

CREATE TABLE big_polygon as
SELECT (ST_Dump( ST_GeomFromText('a multiypolygon geom goes here',4326))).geom as geom;

-- It is always great to put a primary key on the table
ALTER table big_polygon ADD Column gid serial PRIMARY KEY;

-- Create the index
CREATE INDEX idx_big_polygon_geom
on big_polygon
USING gist(geom);

-- To give the database some information about how the index looks
analyze big_polygon;

-- Then you go:
SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1, big polygon WHERE ST_Intersects ( big_polygon.geom,position) 
ORDER BY userid, timestamp desc;

由于几个原因,这应该更快。


感谢Nicklas的出色答复。抱歉,我没有提到我有多个多边形,它们已经存储在带有索引的表中。但是我想直接提供geom数据会更快。但是,我会按照您的建议尝试,但仍然需要很长时间!还有其他建议吗?
萨拉2012年

@Sara。好的,所以您确实尝试按照我对ST_Dump的建议将多几何体拆分为单个几何体?
NicklasAvén2012年

我们在谈论几个用户职位?多少个大多边形?您从big_polygons_table;的SELECT ST_npoints(geom)中得到什么?
NicklasAvén'02

对不起,不好意思,让我为您解释更多有关表格的信息:我有table1,其中包含一个geom列,该列大约有230行,并且每行中都有一个多边形(它们代表国家/地区,因此大小会有所不同) ,并且在the_geom col中具有索引。Table2包含位置列(点),时间戳,用户标识和id(pk)以及使用(位置,时间戳,用户标识)创建的3个索引。此表非常大,大约103496003行,最大ST_npoints数为1440430,最小数为16.对不起,如果让您感到困惑,但我真的需要您的帮助!谢谢
萨拉

2

这取决于您需要哪种质量-精度。您显然可以使用以下方法简化多边形:http : //postgis.net/docs/ST_Simplify.html

在开发GIS应用程序期间,我经常要做的是思考最小化数据的最佳方法。例如。例如,在边界框中预先选择多边形。-根据缩放级别,您不需要超精确的结果(st_simplify),依此类推...

希望对您有所帮助!


感谢Martin的快速回应。我的问题是我需要结果非常准确,所以我认为此功能对我没有帮助!但感谢您的建议
萨拉(Sara)2012年

0

根据您的postgres和/或sql专业知识,您有几种选择:

  1. 通过EXPLAIN命令分析查询,以了解您是否遇到了特定的瓶颈。警告:有时输出EXPLAIN可能很难理解

  2. 如果您希望表1中的大部分或大部分几何图形都不会与多边形相交,则可以尝试对较简单的多边形应用初步条件(例如,通过将多边形分割成较小的部分),然后仅在以下位置运行较重的多边形相交这些结果。请参阅下面的示例。

  3. 当且仅当CPU是瓶颈(即服务器被卡住计算交叉口)我呆呆地建议你得到一个更大,更快,更强大的CPU或租一次性高CPU实例关闭亚马逊的EC2和消灭它,当你做完了

查询项目2的示例:

SELECT DISTINCT ON (st1.userid) st1.userid ,ST_AsText(st1.position), st1.timestamp  
FROM (
    select userid, position, timestamp from table1 
    WHERE ST_Intersects ( YOUR_MULTIPOL_BOUNDS_HERE,position)
) as st1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes     here',4326),st1.position) 
ORDER BY st1.userid, st1.timestamp desc

为了提高性能,您还可以临时将子选择st1实例化为表,以便对其进行索引。

@Nicklas在评论中指出建议2的示例不应有帮助。他是正确的,但我认为我(部分)也是正确的。

实际上,似乎是在去年11月才对Postgis ML提出(并回答)了一个非常类似的问题:

http://postgis.refractions.net/pipermail/postgis-users/2011-November/031344.html

并建议实际上是分解多边形,以便索引可以最有效地过滤出错误的相交点,否则这些错误的相交点将由简单的边界检查触发。


建议2应该无济于事,因为这正是索引的作用。这样,该构造将再次执行相同的操作。
NicklasAvén2012年

@NicklasAvén您说得对,我修改了答案
unicoletti

0

使用 ST_SubDivide()

对于Postgis 2.2版,您可以使用ST_SubDivide

ST_Subdivide —返回一组几何,其中该组中的任何几何都没有超过指定数量的顶点。

setof geometry ST_Subdivide(geometry geom, integer max_vertices=256);

你也可以

  • 使用临时表
  • 索引

在这里,我们用于ST_SubDivide将多边形分解为具有10个以下顶点的子多边形。

CREATE TEMP TABLE divided AS
SELECT ST_SubDivide(bigmultipolygon,10)::geometery AS t(geom);

CREATE INDEX divided_idx ON divided USING gist(geom);

然后

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1
JOIN divided AS d
  ON ST_Intersects( d.geom, position )
ORDER BY userid, timestamp desc;

请勿执行上述操作,否则会导致舍入错误

通用调音

另请参阅文档中标题为“ 性能提示”的部分。确保已正确调整。考虑提高max_parallel_workers_per_gather利用并行化的能力(当前默认为关闭)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.