PostgisでのArcGISのような速度の取得


62

私は1年の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)

言い換えると、ArcGISよりもPostgisでこの共通部分を実行するのに1500%長い時間が必要です。これは、私の最も単純なクエリの1つです。

ArcGISが高速に実行されると思われる理由の1つは、インデックスの改善によるものです。最近、一部のプログラマはこれらのインデックスがどのように機能するかを理解しました。Postgisでこれらのインデックスを作成する方法(またはインデックスを模倣するテーブルを作成する方法)を知っている人がいるかどうか疑問に思います。おそらくこれはPostgisの速度の問題のほとんどを解決するでしょう。特にArcGISは4 GBのRAMしか使用できませんが、postgisサーバーの最大4倍のRAMを使用できるため、何らかの方法が必要だと思います。

もちろん、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から6 GBに増やし、次のコマンドを実行して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. 座標系を中央テキサスフィートに設定(srid 2277)
  3. ドロップダウンメニューから交差ツールを使用する

Postgis

次を使用して区画をインポートします。

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分かかるために間違っていることはまったくわかりません!


2
PostGISでは、バウンディングボックスの交差チェックを追加して物事をスピードアップするのが一般的なイディオムです。WHERE句に「AND a.geom && b.geom」を追加してみて、どの程度の違いが生じるかを確認してください。
ショーン

2
st_intersects()には、postgis 2.xで交差テストを実行する前に境界ボックスクエリが含まれているため、残念ながら時間を節約できません。
THX1138

1
あなたは結果を分析し、投稿EXPLAIN使用してクエリを実行することができます
ネイサンW

1
また、postgisとarcgisで異なるデータセットを実行していることにも注意する必要があります。これは、postgisで受け入れられるようにneexを有効にする必要があるからです。
ニックラスアベン

2
データセットを見て取得することは可能ですか?
ニックラスアベン

回答:


87

別のアプローチ。痛みが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なしでも高速になる可能性があります。


13
おかげで3.63分になりました!組合がもっと速くなるとは思っていなかったでしょう。この答えにより、これからクエリを実行する方法を再考することができます。
THX1138

2
これはとてもクールです。仕事でst_intersectionクエリに30分以上かかったケースがありましたが、今ではそれを回避する方法を知っています:)
ネイサンW

1
この質問は私にPostgisを学ばせました!PostgisがArcgisと肩を並べて走るのを見て、今日はよく眠ります:
vinayan

2
Martin Davisによるもう1つの機能強化として、「in or out?」をインライン化できます。CASEステートメントを使用してSELECTに質問し、そのようにUNIONを避けます。
ポールラムジー

2
UNION2つのクエリから重複行を削除しますが、これら2つのクエリの結果セットに同じ行を含めることはできません。したがってUNION ALL、ここでは重複チェックをスキップするのが適切です。(UNIONあまり使用していませんが、一般的に、使用する時間帯はずっと頻繁に使用していますUNION ALL。)
jpmc26

4

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

いいえ、結果の交差ポリゴンが必要ですが、クエリは、クエリのバイナリのtrue / falseテスト部分ではなく、すべての問題が交差の生成にあることを非常にうまく示しています。そして、真/偽のコードは高度に最適化されていますが、交差の生成は最適化されていないため、それは非常に期待されています。
ポールラムジー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.