我是PostgreSQL和PostGIS的新手,但这个问题并非无足轻重。我正在使用PostgreSQL 9.5和PostGIS 2.2。
我需要运行一些耗费大量时间的查询。
首先,让我用非GIS术语解释这个问题:
基本上,我有一组数十万点分布在一个大约五十万平方公里(国家)的领土上。
在这片领土上,我有来自各种数据库的十几个区域。在每一组中,我都有几百到几千个区域。我想找出这些领域中的哪些点。
现在,我目前如何解决GIS方面的问题:
每组区域都是一个Postgresql表,其中包含 multipolygon 类型的几何列,并且具有前几百到几千条记录所解释的内容。
所有这些表都包含在模式 donnees 中,但我为这些操作使用了不同的模式,称为 traitements 。
因此,该过程将所有几何图形合并为一个几何图形,然后b /查找此几何图形中包含的点。
问题在于,如果步骤a /花费了合理的时间(几分钟),步骤b /需要永远。
我目前只处理我必须处理的点的样本(大约1%,即大约7000),并且在几个小时之后它没有完成(数据库连接最终超时)。
我通过将返回行数限制为10或50来进行测试运行,并且它仍然需要大约半小时。
如果你想知道的话,我正在使用带有4个CPU和8 Gb RAM的Linux Mint 18机器。
我在几何列上创建了索引。所有几何列都使用相同的SRID。
创建表格
CREATE TABLE traitements.sites_candidats (
pkid serial PRIMARY KEY,
statut varchar(255) NOT NULL,
geom geometry(Point, 2154)
);
CREATE UNIQUE INDEX ON traitements.sites_candidats (origine, origine_id ) ;
CREATE INDEX ON traitements.sites_candidats (statut);
CREATE INDEX sites_candidats_geométrie ON traitements.sites_candidats USING GIST ( geom );
CREATE TABLE traitements.zones_traitements (
pkid serial PRIMARY KEY,
définition varchar(255) NOT NULL,
geom geometry (MultiPolygon, 2154)
);
CREATE UNIQUE INDEX ON traitements.zones_traitements (définition) ;
CREATE INDEX zones_traitements_geométrie ON traitements.zones_traitements USING GIST ( geom );
请注意,我只在表 traitements 中指定了 geom 列的几何类型,因为我想指定SRID,但我不确定正确的语法是什么适用于任何类型的几何。也许" geom geometry(Geometry,2154)" ?
合并各组区域的所有几何图形:
如前所述,所有表都具有多边形类型的几何形状。
这是我用来合并其中一个表的所有几何的代码:
INSERT INTO traitements.zones_traitements
( définition, , geom )
VALUES
(
'first-level merge',
(
SELECT ST_Multi(ST_Collect(dumpedGeometries)) AS singleMultiGeometry
FROM
(
SELECT ST_Force2D((ST_Dump(geom)).geom) AS dumpedGeometries
FROM donnees.one_table
) AS dumpingGeometries
)
) ;
我发现某些记录中的某些几何图形是3D的,这就是我使用_ST_Force2D _的原因。
我对所有表执行此操作,然后使用:
再次合并几何INSERT INTO traitements.zones_traitements
( définition, geom )
VALUES
(
'second-level merge',
(
SELECT ST_Multi(ST_Collect(dumpedGeometries)) AS singleMultiGeometry
FROM
(
SELECT (ST_Dump(geom)).geom AS dumpedGeometries
FROM traitements.zones_traitements
WHERE définition != 'second-level merge'
) AS dumpingGeometries
)
) ;
如前所述,这些查询需要几分钟,但没关系。
不是永远需要的查询:
SELECT pkid
FROM traitements.sites_candidats AS sites
JOIN (
SELECT geom FROM traitements.zones_traitements
WHERE définition = 'zones_rédhibitoires' ) AS zones
ON ST_Contains(zones.geom , sites.geom)
LIMIT 50;
分析问题:
显然,子查询选择需要花费大量时间的点,而不是更新。
所以我在查询上运行了一个EXPLAIN(ANALYZE,BUFFERS):
EXPLAIN (ANALYZE, BUFFERS)
SELECT pkid
FROM traitements.sites_candidats AS sites
JOIN (
SELECT geom FROM traitements.zones_traitements
WHERE définition = 'second_level_merge' ) AS zones
ON ST_Contains(zones.geom , sites.geom)
LIMIT 10;
---------------------------------
"Limit (cost=4.18..20.23 rows=1 width=22) (actual time=6052.069..4393634.244 rows=10 loops=1)"
" Buffers: shared hit=1 read=688784"
" -> Nested Loop (cost=4.18..20.23 rows=1 width=22) (actual time=6052.068..4391938.803 rows=10 loops=1)"
" Buffers: shared hit=1 read=688784"
" -> Seq Scan on zones_traitements (cost=0.00..1.23 rows=1 width=54939392) (actual time=0.016..0.016 rows=1 loops=1)"
" Filter: (("définition")::text = 'zones_rédhibitoires'::text)"
" Rows Removed by Filter: 17"
" Buffers: shared hit=1"
" -> Bitmap Heap Scan on sites_candidats sites (cost=4.18..19.00 rows=1 width=54) (actual time=6052.044..4391260.053 rows=10 loops=1)"
" Recheck Cond: (zones_traitements.geom ~ geom)"
" Filter: _st_contains(zones_traitements.geom, geom)"
" Heap Blocks: exact=1"
" Buffers: shared read=688784"
" -> Bitmap Index Scan on "sites_candidats_geométrie" (cost=0.00..4.18 rows=4 width=0) (actual time=23.284..23.284 rows=3720 loops=1)"
" Index Cond: (zones_traitements.geom ~ geom)"
" Buffers: shared read=51"
"Planning time: 91.967 ms"
"Execution time: 4399271.394 ms"
我不知道如何阅读此输出。
尽管如此,我怀疑查询是如此之慢,因为通过将所有这些多边形合并为一个多边形而获得的几何体。
问题:
使用不同类型的几何图形来合并其他几何图形会更好吗,比如 GeometryCollection ?
在这种情况下,索引如何工作?
是否比ST_Contains()效率更高?
答案 0 :(得分:0)
再次,谢谢。
我得出了与你的建议相同的结论:不是将所有数千个多边形合并成一个巨大的多边形,其bbox太大,将所有多边形分解为简单的多边形会更有效率ST_Dump并将这些插入到具有适当索引的专用表中。 然而,要做到这一点,我首先必须纠正几何形状:某些多边形确实具有无效的几何形状。 St_MakeValid会使90%的有效多边形成为多边形,但其余部分将转换为GeometryCollections或MultilineStrings。为了纠正这些,我使用了ST_Buffer,缓冲区为0.01米,其结果是正确的多边形。 一旦完成,我的所有多边形都是有效的,我可以将它们转储成简单的多边形。
这样做,我将搜索时间减少了+/- 5000!
:d