Postgis ST_Intersects在两个表之间真的(真的)很慢

时间:2019-07-01 13:08:21

标签: postgis

我正在尝试在两个表之间进行空间连接:

  1. 表1:397265的特征(在geom字段上具有gist索引)
  2. 表2:73个特征(在geom字段上具有gist索引)

表1和表2具有相同的SRID。

我做了很多测试,并且这些表之间的空间连接花了几天的时间(5天后我杀死了查询)。我试图通过解释分析来了解为什么它这么慢:

EXPLAIN ANALYZE 
SELECT 
    table1.id,  table2.id
FROM table1
INNER JOIN table2 ON ST_Intersects(
        ST_Buffer(table1.geom,0),
        ST_Buffer(table2.geom,0)
)

但是目前,我仍在等待结果,因为EXPLAIN ANALYZE确实执行了查询。

如果我只做一个解释,这里是结果:

"Gather  (cost=1000.00..3820127.08 rows=9667 width=40)"
"  Workers Planned: 3"
"  ->  Nested Loop  (cost=0.00..3818111.26 rows=3118 width=40)"
"        Join Filter: ((st_buffer(table2.geom, '0'::double precision) && st_buffer(table1.geom, '0'::double precision)) AND _st_intersects(st_buffer(table2.geom, '0'::double precision), st_buffer(table1.geom, '0'::double precision)))"
"        ->  Parallel Seq Scan on table1  (cost=0.00..21964.50 rows=128150 width=344)"
"        ->  Seq Scan on table2  (cost=0.00..9.73 rows=73 width=714516)"

我还更新了有关计算机配置的postgresql配置文件:

shared_buffers = 8GB
effective_cache_size = 24GB
maintenance_work_mem = 2GB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 4
effective_io_concurrency = 2
work_mem = 10485kB
min_wal_size = 1GB
max_wal_size = 2GB
max_worker_processes = 7
max_parallel_workers_per_gather = 4
max_parallel_workers = 7

你能告诉我这么久吗?

3 个答案:

答案 0 :(得分:3)

不使用空间索引。

您可以放下buffer(可以先修复几何形状。)

INNER JOIN table2 ON ST_Intersects(table1.geom,table2.geom)

或者您可以在缓冲的几何图形上创建索引

CREATE INDEX geom_idx ON table1 USING gist (ST_Buffer(table1.geom,0));

答案 1 :(得分:1)

正如其他评论所建议的那样,修复几何形状更好。我猜您使用零距离的缓冲区来重建无效的几何。因此,最好的方法是

UPDATE table1 SET geom = st_buffer(geom,0);
UPDATE table2 SET geom = st_buffer(geom,0);

然后重新索引表格(通过几何重建其原始要点索引)

此外,根据几何图形的性质,索引可能效率不高。 索引本身基本上是每种几何(多边形或线性形状周围的矩形)的一组边界框,并且确定哪些矩形先相交然后在对中定义精确的几何相交要快得多。但是,如果您的多边形太大而大多数矩形相交和/或形状太复杂,则可能会降低连接速度。

此外,就点密度而言,您的数据可能很繁重,这也减慢了算法的速度,并且可以在不严重损害结果的情况下将其删除,尤其是在此数据在空间上不太准确的情况下。您可以尝试简化数据,例如

ALTER table1 ADD COLUMN geom_simplified geom(<your geom type and srid>);
UPDATE table1 SET geom_simplified = st_snaptogrid(geom,<relevant rounding number depending on your srid and desired accuracy>);

签出this

答案 2 :(得分:0)

谢谢@jgh的回答,您已经找到了问题。未使用索引。 我永远也找不到它,因为对我来说很明显,即使使用了缓冲区也使用了索引。

我尝试清除数据,但是有很多错误。所以我决定使用您的解决方案(ST_Buffer()上的索引)

我的查询现在需要14个小时。关于表2中的功能数量,仍然有很多时间,但是至少查询结束了。

"Gather  (cost=1000.14..116847.28 rows=397265 width=8) (actual time=70.548..51214359.966 rows=415151 loops=1)"
"  Workers Planned: 3"
"  Workers Launched: 3"
"  ->  Nested Loop Left Join  (cost=0.14..76120.78 rows=128150 width=8) (actual time=1312.989..51210248.284 rows=103788 loops=4)"
"        ->  Parallel Seq Scan on table1  (cost=0.00..21964.50 rows=128150 width=338) (actual time=0.009..3485.290 rows=99316 loops=4)"
"        ->  Index Scan using table2_idx_buffer on table2  (cost=0.14..0.41 rows=1 width=714516) (actual time=460.535..515.510 rows=0 loops=397265)"
"              Index Cond: (st_buffer(table1.geom, '0'::double precision) && st_buffer(geom, '0'::double precision))"
"              Filter: _st_intersects(st_buffer(table1.geom, '0'::double precision), st_buffer(geom, '0'::double precision))"
"              Rows Removed by Filter: 3"
"Planning time: 0.227 ms"
"Execution time: 51214434.490 ms"