多边形搜索中的点太慢

时间:2018-11-29 12:02:29

标签: postgresql performance postgis point-in-polygon

我使用Postgis扩展来确定给定的点(地理坐标)是否在多边形中。问题是查询太慢。每100点需要大约7秒钟的时间。

有一些信息:

db=$ \set mpol ST_GeomFromText(pg_read_file($$large_pol.txt$$))

db=# select st_npoints(:mpol);
 st_npoints 
------------
      39522
(1 row)

Time: 125.451 ms


db=# select count(*)
     from (select * from cargos limit 100) c
     where st_within(c.geo_origin_point::geometry, :mpol);

 count 
-------
     0
(1 row)

Time: 7532.868 ms (00:07.533)

我已经尝试使用ST_Simplify简化多边形,但是到目前为止,这根本没有影响查询的执行时间。

db=# select st_npoints(st_simplify(:mpol, 1));
 st_npoints 
------------
         14
(1 row)

Time: 99.213 ms

db=# select count(*)
     from (select * from cargos limit 100) c
     where st_within(c.geo_origin_point::geometry, st_simplify(:mpol, 1));

 count 
-------
     0
(1 row)

Time: 7667.504 ms (00:07.668)

表中货物的 geo_origin_point 列:

db=# \dS cargos;
   geo_origin_point     | geography(Point,4326)       |           |          
Indexes:
    "cargos_geo_origin_point" gist (geo_origin_point)

我想,即使100分需要这么长时间,也肯定有问题。

由于某些原因未使用索引:

db=# explain analyze select count(*) from (select * from cargos limit 100) c where st_within(c.geo_origin_point, st_simplify(:mpol, 1));
                                                                  QUERY PLAN                                                                  
----------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=31.31..31.32 rows=1 width=8) (actual time=8698.561..8698.562 rows=1 loops=1)
   ->  Subquery Scan on c  (cost=0.00..31.23 rows=33 width=0) (actual time=8698.555..8698.555 rows=0 loops=1)
         Filter: st_within(c.geo_origin_point, st_simplify(st_geomfromtext(pg_read_file('moscow_obl_pol.txt'::text)), '1'::double precision))
         Rows Removed by Filter: 100
         ->  Limit  (cost=0.00..4.48 rows=100 width=2633) (actual time=0.042..0.580 rows=100 loops=1)
               ->  Seq Scan on cargos  (cost=0.00..2121.67 rows=47367 width=2633) (actual time=0.038..0.516 rows=100 loops=1)
 Planning Time: 0.186 ms
 Execution Time: 8698.641 ms
(8 rows)

更新:

我刚刚发现,如果不从文件中加载多边形数据,查询将几乎被立即执行。太奇怪了。

db=# select count(*) from cargos c where st_within(c.geo_origin_point, ST_GeomFromText('MULTIPOLYGON(((-71.1031880899493 42.3152774590236, -71.1031627617667 42.3152960829043,-71.102923838298 42.3149156848307, -71.1023097974109 42.3151969047397,-71.1019285062273 42.3147384934248, -71.102505233663 42.3144722937587,-71.10277487471 42.3141658254797, -71.103113945163 42.3142739188902,-71.10324876416 42.31402489987, -71.1033002961013 42.3140393340215,-71.1033488797549 42.3139495090772, -71.103396240451 42.3138632439557,-71.1041521907712 42.3141153348029, -71.1041411411543 42.3141545014533,-71.1041287795912 42.3142114839058, -71.1041188134329 42.3142693656241,-71.1041112482575 42.3143272556118, -71.1041072845732 42.3143851580048,-71.1041057218871 42.3144430686681, -71.1041065602059 42.3145009876017,-71.1041097995362 42.3145589148055, -71.1041166403905 42.3146168544148,-71.1041258822717 42.3146748022936, -71.1041375307579 42.3147318674446,-71.1041492906949 42.3147711126569, -71.1041598612795 42.314808571739,-71.1042515013869 42.3151287620809, -71.1041173835118 42.3150739481917,-71.1040809891419 42.3151344119048, -71.1040438678912 42.3151191367447,-71.1040194562988 42.3151832057859, -71.1038734225584 42.3151140942995,-71.1038446938243 42.3151006300338, -71.1038315271889 42.315094347535,-71.1037393329282 42.315054824985, -71.1035447555574 42.3152608696313,-71.1033436658644 42.3151648370544, -71.1032580383161 42.3152269126061,-71.103223066939 42.3152517403219, -71.1031880899493 42.3152774590236)))',4326));

 count 
-------
     0
(1 row)

Time: 2.251 ms

1 个答案:

答案 0 :(得分:2)

第一个查询st_contains(c.geo_origin_point::geometry, :mpol);永远不会返回任何内容,因为它查找包含在点中的多边形。您将需要交换参数,或像第二个查询一样使用st_within。< / p>

瓶颈是不使用空间索引。您已为geography编制了索引,但正在使用到geometry的转换。然后尝试索引转换:

CREATE INDEX cargos_geom_origin_point ON public.cargos USING gist((geo_origin_point::geometry));