Postgis’te ArcGIS benzeri hıza sahip olmak


62

Postgis 2.0'ı bir yılın 3/4'ü boyunca kullanıyorum ve gerçekten kullanmaktan zevk alırken, aşırı sorgu işlem süresi onu kullanım durumum için temelde kullanılamaz hale getirdi.

Sık sık yüz binlerce çoklu poligona sahip belediye veri kümeleri üzerinde ağır coğrafi işlemler yapmaya meyilliyim. Bu multipolygonlar bazen çok düzensiz şekillenir ve multipolygon başına 4 ile 78.000 puan arasında değişebilir.

Örneğin, bir parsel veri kümesini 329 çokgen içeren bir yargı veri kümesine sahip 329,152 çok köşeli küme ile kestiğimde, tüketilen toplam süre için aşağıdaki istatistikleri alıyorum:

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

Başka bir deyişle, Postgis'te bu kavşağı yapmak için ArcGIS'e göre% 1500 daha fazla zaman gerekir - ve bu benim en basit sorgularımdan biri!

ArcGIS'in sözde daha hızlı çalışmasının sebeplerinden biri, daha iyi endekslerden kaynaklanıyor. Bazı programcılar son zamanlarda bu endekslerin nasıl çalıştığını öğrendiler ve kimsenin bu endeksleri Postgis'te (veya endeksleri taklit edecek tablolar oluşturacaklarını) nasıl yapabileceğini bilip bilmediğini merak ediyorum. Belki de bu Postgis'teki hız sorunlarının çoğunu çözecektir. Umarım bir yolun olması gerektiğini umarım, özellikle de ArcGIS postgis sunucum için 4 kata kadar kullanabildiğimde sadece 4 GB RAM kullanabilir.

Tabii ki postgis'in yavaş çalışmasının birçok nedeni var, bu yüzden sistem şartnamemin ayrıntılı bir versiyonunu sunacağım:

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

Ayrıca VM'nin oluşturulması da dahil olmak üzere postgis'i kurmak için kullandığım tüm kurulum sürecini detaylandırıyorum .

Ayrıca conf dosyasını paylaşılan belleği varsayılan 24 MB'tan 6 GB'a çıkardım ve postgres'lerin çalışabilmesi için aşağıdaki komutları çalıştırdım:

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

Söyleyebileceğim kadarıyla performans açısından kesinlikle farkedilir hiçbir şey yapmaz.

İşte bu test için kullandığım verilere bağlantılar:

  1. Koliler: tcad_parcels_06142012.shp.zip dan Austin City
  2. Yargı: Yargı Sınırları dan Austin City

Verileri işlemek için attığım adımlar:

ArcGIS

  1. ArcMap'e veri setleri ekle
  2. Koordinat sistemini merkezi texas feet'e ayarla (2277 no'lu srid)
  3. Açılır menüden kesişim aracını kullanın

PostGIS

Parselleri kullanarak içe aktar:

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

Yetki alanlarını kullanarak ithalat:

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

Parsellerdeki geçersiz geometrileri temizleyin:

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;

Yargı bölgelerinde geçersiz geometri temizleyin:

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;

Küme çalıştır:

cluster;

Vakum analizini çalıştırın:

vacuum analyze;

Temizlenmiş masalarda kesişme yapın:

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);

Kavşak sorgusu analizini açıklayın:

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)

Okuduğum her şeyden sonra, kesişim sorgum verimlidir ve sorgunun temiz geometri üzerinde 56 dakika sürmesi için neyi yanlış yaptığım hakkında hiçbir fikrim yok!


2
PostGIS'te işleri hızlandırmak için bir sınırlayıcı kutu kesişme kontrolü eklemek yaygın bir deyimdir. WHERE yan tümcesine 'AND a.geom && b.geom' eklemeyi deneyin ve ne kadar fark yarattığını görün.
Sean,

2
st_intersects (), postgis 2.x içinde herhangi bir kesişim testi yapmadan önce sınırlayıcı bir kutu sorgusu içerir, bu nedenle ne yazık ki zaman kazanmaz.
THX1138

1
EXPLAIN ANALYSE kullanarak sorgunuzu çalıştırabilir ve sonuçları gönderebilir misiniz
Nathan W

1
Ayrıca, postgis ve arggis'te farklı veri kümeleri çalıştırdığınızı da bilmelisiniz;
Nicklas Avén

2
Veri setlerini incelemek mümkün müdür?
Nicklas Avén

Yanıtlar:


87

Farklı yaklaşım. Ağrının ST_Iersection'da olduğunu ve doğru / yanlış testlerin hızlı olduğunu bilmek, kavşaktan geçen geometri miktarını en aza indirmeye çalışmak işleri hızlandırabilir. Örneğin, tamamen bir yargı alanında bulunan parsellerin kırpılması gerekmez, ancak ST_Iersterection hala herhangi bir yeni geometri oluşturmak zorunda olmadığının farkına varmadan önce kesişim kaplamasının bir kısmını inşa etme sorununa devam edecektir. Yani bu

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);

Hatta tereddüt

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 ile daha da hızlı olabilir.


13
Teşekkürler, beni 3.63 dakikaya indirdi! Bir sendikanın daha hızlı olacağını hiç düşünmezdim. Bu cevap gerçekten bundan sonra sorgularımı nasıl yaptığımı yeniden düşündürecek.
THX1138

2
Bu çok havalı. St_intersection sorgumun 30mins + kullandığı bir işim vardı ve şimdi bundan nasıl kaçınabileceğimi biliyorum :)
Nathan W

1
Bu soru bana Postgis öğrendi! Bugün iyi uyuyacağım Postgis'i Arcgis :-) ile omuz omuza koşarken görmek
vinayan

2
Martin Davis'ten bir geliştirme daha, "giriş veya çıkış" satır içi olabilir. bir CASE ifadesi kullanarak SELECT'i sorgulayın ve UNION'dan bu şekilde kaçının.
Paul Ramsey

2
UNIONiki sorgudaki çoğaltılmış satırları ortadan kaldırır, ancak bu iki sorgu sonuç kümelerinde aynı satıra sahip olamaz. Böylece UNION ALL, yinelenen kontrolü atlayan, burada uygun olur. (Çok UNIONfazla kullanmıyorum , ancak genelde yaptığım zamanlardan çok daha sık kullanıyorum UNION ALL.)
jpmc26 21:06

4

Parçayı atlarsan ne olur "st_multi(st_intersection(a.geom,b.geom))"?

Aşağıdaki sorgu onsuz aynı şeyi ifade etmiyor mu? Verdiğin verilere koştum.

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);

Yapılandırma

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"

Sonuçları Analiz Et

"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"

Hayır, sonuçta ortaya çıkan kesişme çokgenlerini istiyor, ancak sorgunuz çok güzel bir şekilde tüm acının, sorgunun ikili / yanlış test bölümünde değil, kesişme neslinde olduğunu gösteriyor. Ve bu oldukça beklenir, çünkü doğru / yanlış kod kavşak oluşturmada değilken oldukça optimize edilmiştir.
Paul Ramsey
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.