나는 지금 일년 중 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
내가 알 수있는 한 이것은 성능면에서 눈에 띄지 않습니다.
이 테스트에 사용한 데이터에 대한 링크는 다음과 같습니다.
- 소포 : tcad_parcels_06142012.shp.zip 에서 텍사스 주 오스틴시
- 관할 구역 : 관할 경계 에서 오스틴, 텍사스의 도시
데이터를 처리하기 위해 취한 단계는 다음과 같습니다.
ArcGIS
- ArcMap에 데이터 세트 추가
- 좌표계를 중앙 텍사스 피트로 설정 (2277 번 분할)
- 드롭 다운 메뉴에서 교차 도구 사용
포스트 지스
다음을 사용하여 소포 가져 오기 :
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"