Postgis에서 ArcGIS와 같은 속도 획득 16.0 GB (10.0 GB on virtual

나는 지금 일년 중 3/4에 Postgis 2.0을 사용해 왔으며 실제로 그것을 사용하는 것을 즐기면서 과도한 쿼리 처리 시간으로 인해 기본적으로 사용 사례에 사용할 수 없게되었습니다.

나는 종종 수십만 개의 다중 다각형을 가진 도시 데이터 세트에 대해 무거운 지오 프로세싱을하는 경향이 있습니다. 이러한 다중 다각형은 때때로 매우 불규칙적으로 형성되며 다중 다각형 당 4 점에서 78,000 점까지 다양합니다.

예를 들어, 525 개의 다중 다각형을 포함하는 관할 구역 데이터 집합과 329,152 개의 다중 다각형으로 구획 데이터 집합을 교차 시키면 총 소비 시간에 대한 다음 통계가 표시됩니다.

ArcGIS 10.0 (on same host with windows 7 OS): 3 minutes
Postgis:56 minutes (not including geometry pre-processing queries)

다시 말해, PostGIs에서 ArcGIS보다이 교차로를 수행하는 데 1500 % 더 많은 시간이 필요합니다. 이것은 더 간단한 쿼리 중 하나입니다!

ArcGIS가 더 빠르게 실행되는 이유 중 하나는 더 나은 색인 때문입니다. 일부 프로그래머는 최근에 이러한 인덱스의 작동 방식을 알아 냈으며 Postgis에서 인덱스를 작성하는 방법 (또는 인덱스를 모방 할 테이블을 작성하는 방법)을 아는 사람이 있는지 궁금합니다. 아마도 이것은 Postgis의 대부분의 속도 문제를 해결할 것입니다. 특히 ArcGIS는 4GB의 RAM 만 사용할 수 있지만 postgis 서버의 경우 최대 4 배를 사용할 수 있기 때문에 어떤 방법이 필요하기를 바랍니다.

물론 postgis가 느리게 실행될 수있는 여러 가지 이유가 있으므로 자세한 시스템 사양을 제공 할 것입니다.

Machine: Dell XPS 8300
Processor: i7-2600 CPU @ 3.40 GHz 3.40 GHz
Memory: Total Memory 16.0 GB (10.0 GB on virtual machine)

Platform: Ubuntu Server 12.04 Virtual Box VM

Potgres Version: 9.1.4
Postgis Version: POSTGIS="2.0.1 r9979" GEOS="3.3.5-CAPI-1.7.5" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.1, released 2012/05/15" LIBXML="2.7.8" LIBJSON="UNKNOWN" TOPOLOGY RASTER

또한 VM 자체 작성을 포함하여 postgis를 설정하는 데 사용한 전체 설치 프로세스에 대해서도 자세히 설명합니다 .

또한 conf 파일에서 공유 메모리를 기본 24MB에서 6GB로 늘리고 postgres를 실행할 수 있도록 다음 명령을 실행했습니다.

sudo sysctl -w kernel.shmmax=7516192768 (I know this setting is deleted every time you restart the OS)
sudo /etc/init.d/postgresql restart

내가 알 수있는 한 이것은 성능면에서 눈에 띄지 않습니다.

이 테스트에 사용한 데이터에 대한 링크는 다음과 같습니다.

  1. 소포 : tcad_parcels_06142012.shp.zip 에서 텍사스 주 오스틴시
  2. 관할 구역 : 관할 경계 에서 오스틴, 텍사스의 도시

데이터를 처리하기 위해 취한 단계는 다음과 같습니다.

ArcGIS

  1. ArcMap에 데이터 세트 추가
  2. 좌표계를 중앙 텍사스 피트로 설정 (2277 번 분할)
  3. 드롭 다운 메뉴에서 교차 도구 사용

포스트 지스

다음을 사용하여 소포 가져 오기 :

shp2pgsql -c -s 2277 -D -i -I -W UTF-8 "tcad_parcels_06142012.shp" "public"."tcad_parcels_06142012" |psql -d postgis_testing -U postgres -h local_ip -p 5432

다음을 사용하여 관할 구역 가져 오기 :

shp2pgsql -c -s 2277 -D -i -I -W UTF-8 "jurisdictions.shp" "public"."jurisdictions" |psql -d postgis_testing -U postgres -h local_ip -p 5432

구획에서 유효하지 않은 지오메트리를 청소하십시오.

DROP TABLE IF EXISTS valid_parcels;
CREATE TABLE valid_parcels(
  gid serial PRIMARY KEY,
  orig_gid integer,
  geom geometry(multipolygon,2277)
);
CREATE INDEX ON valid_parcels USING gist (geom);
INSERT INTO valid_parcels(orig_gid,geom)
  SELECT
    gid
    orig_gid,
    st_multi(st_makevalid(geom))
  FROM
    tcad_parcels_06142012;
CLUSTER valid_parcels USING valid_parcels_geom_idx;

관할 구역에서 유효하지 않은 지오메트리 정리 :

DROP TABLE IF EXISTS valid_jurisdictions;
CREATE TABLE valid_jurisdictions(
  gid serial PRIMARY KEY,
  orig_gid integer,
  geom geometry(multipolygon,2277)
);
CREATE INDEX ON valid_jurisdictions USING gist (geom);
INSERT INTO valid_jurisdictions(orig_gid,geom)
  SELECT
    gid
    orig_gid,
    st_multi(st_makevalid(geom))
  FROM
    jurisdictions;
CLUSTER valid_jurisdictions USING valid_jurisdictions_geom_idx;

클러스터를 실행하십시오.

cluster;

진공 분석을 실행하십시오.

vacuum analyze;

정리 된 테이블에서 교차를 수행하십시오.

CREATE TABLE parcel_jurisdictions(
  gid serial primary key,
  parcel_gid integer,
  jurisdiction_gid integer,
  isect_geom geometry(multipolygon,2277)
);
CREATE INDEX ON parcel_jurisdictions using gist (isect_geom);

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
  SELECT
    a.orig_gid parcel_gid,
    b.orig_gid jurisdiction_gid,
    st_multi(st_intersection(a.geom,b.geom))
  FROM
    valid_parcels a, valid_jurisdictions b
  WHERE
    st_intersects(a.geom,b.geom);

교차로 분석 분석 설명 :

Total runtime: 3446860.731 ms
        Index Cond: (geom && b.geom)
  ->  Index Scan using valid_parcels_geom_idx on valid_parcels a  (cost=0.00..11.66 rows=2 width=1592) (actual time=0.030..4.596 rows=1366 loops=525)
  ->  Seq Scan on valid_jurisdictions b  (cost=0.00..113.25 rows=525 width=22621) (actual time=0.009..0.755 rows=525 loops=1)
Nested Loop  (cost=0.00..61428.74 rows=217501 width=24213) (actual time=2.625..3445946.889 rows=329152 loops=1)
  Join Filter: _st_intersects(a.geom, b.geom)

내가 읽은 모든 것에서 교차 쿼리는 효율적이며 쿼리가 깨끗한 지오메트리에서 56 분이 걸리는 것에 대해 내가 뭘 잘못하고 있는지 전혀 모른다!



답변

다른 접근법. 고통이 ST_Intersection에 있고 참 / 거짓 테스트가 빠르다는 것을 알면 교차점을 통과하는 형상의 양을 최소화하려고하면 속도가 빨라질 수 있습니다. 예를 들어, 관할 구역에 완전히 포함 된 소포는 잘릴 필요는 없지만 ST_Intersection은 새로운 지오메트리를 생성 할 필요가 없다는 것을 깨닫기 전에 교차로 오버레이의 일부를 작성하는 데 어려움을 겪을 수 있습니다. 그래서 이건

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
SELECT
  a.orig_gid AS parcel_gid,
  b.orig_gid AS jurisdiction_gid,

  st_multi(st_intersection(a.geom,b.geom)) AS geom
FROM
  valid_parcels a, valid_jurisdictions b
WHERE
  st_intersects(a.geom, b.geom) and not st_within(a.geom, b.geom)
UNION ALL
SELECT
  a.orig_gid AS parcel_gid,
  b.orig_gid AS jurisdiction_gid,
  a.geom AS geom
FROM
  valid_parcels a, valid_jurisdictions b
WHERE
  st_within(a.geom, b.geom);

또는 심지어 터져

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
SELECT
  a.orig_gid AS parcel_gid,
  b.orig_gid AS jurisdiction_gid,
  CASE
     WHEN ST_Within(a.geom,b.geom)
     THEN a.geom
     ELSE ST_Multi(ST_Intersection(a.geom,b.geom))
  END AS geom
FROM valid_parcels a
JOIN valid_jurisdictions b
ON ST_Intersects(a.geom, b.geom)

UNION없이 더 빠를 수도 있습니다.


답변

"st_multi(st_intersection(a.geom,b.geom))"부품 을 생략하면 어떻게됩니까?

아래 쿼리가 없으면 동일한 쿼리를 의미하지 않습니까? 나는 당신이 제공 한 데이터에서 그것을 실행했습니다.

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
  SELECT
    a.orig_gid parcel_gid,
    b.orig_gid jurisdiction_gid,
    a.geom
  FROM
    valid_parcels a, valid_jurisdictions b
  WHERE
    st_intersects(a.geom,b.geom);

구성

Processor: AMD Athlon II X4 635 2.9 GHz
Memory: 4 GB
Platform: Windows 7 Professional
Potgres Version: 8.4
Postgis Version: "POSTGIS="2.0.1 r9979" GEOS="3.3.5-CAPI-1.7.5" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.1, released 2012/05/15" LIBXML="2.7.8" LIBJSON="UNKNOWN" TOPOLOGY RASTER"

결과 분석

"Nested Loop  (cost=0.00..7505.18 rows=217489 width=1580) (actual time=1.994..248405.616 rows=329150 loops=1)"
"  Join Filter: _st_intersects(a.geom, b.geom)"
"  ->  Seq Scan on valid_jurisdictions b  (cost=0.00..37.25 rows=525 width=22621) (actual time=0.054..1.732 rows=525 loops=1)"
"  ->  Index Scan using valid_parcels_index on valid_parcels a  (cost=0.00..11.63 rows=2 width=1576) (actual time=0.068..6.423 rows=1366 loops=525)"
"        Index Cond: (a.geom && b.geom)"
"Total runtime: 280087.497 ms"

답변