OpenStreetMap PostGISクエリの高速化


12

浸透スキーマを使用して、オランダのOpenStreetMapデータをPostGISデータベース(PostgreSQL 8.3 / PostGIS 1.3.3)にロードしました。これは、すべてのタグがhstoreフィールドに保存されることを意味します。浸透がジオメトリフィールドに作成するGISTインデックスに加えて、タグフィールドに追加のGISTインデックスを作成しました。

空間制約とタグフィールドの制約の両方を使用してクエリを実行しようとすると、思ったよりも遅いことがわかりました。このようなクエリ:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

78レコードを返すのに22秒かかります。

このテーブルには、約5,300万件のレコードがあります。

これを大幅にスピードアップする方法はありますか?PostgreSQL 9でhstoreの実装が大幅に改善されたと聞いたことがありますが、アップグレードは役に立ちますか?


これは、データベース指向の質問私が上で依頼することをお勧めのようですのでdba.stackexchange.com
jcolebrand

2015年の更新-PostGISは、この質問が出されて以来、パフォーマンスが大幅に改善されているため、PostgreSQLのアップグレードと同様に検討してください。
トビースパイト

回答:


5

1つの方法は、関心のあるタグを照会し、それらのレコードを新しいテーブルに配置することです。次に、5300万レコードすべてではなく、新しいテーブルを照会するだけで済みます。データベースを最新の状態に保ちたい場合は、OSMから新しいデータを取得するたびにこのクエリを実行することができます。


2
新しいテーブルを作成するのではなく、代わりにVIEWを作成することを検討してください。この方法では、データのリテラル複製なしで、「クエリ」が元のソースデータにライブリンクされます。
RyanKDalton

7
ビューは、マテリアライズドビューまたは同等のビューでない限り、必ずしもクエリのパフォーマンスを向上させるとは限りません(このトピックに関するSOの質問を参照)。Postgresqlがマテリアライズドビューを直接サポートするとは思いませんが、トリガーを使用して実装できます。
アダムアーマー

2
これは私が現在使用している回避策です。浸透テーブルの更新後、実行するクエリ用に最適化されたいくつかのテーブルを再作成します。もっと良い方法が必要だと感じています。トリガーのトピックに興味があり、トリガーを使用してマテリアルビューを実装する方法を知りたいと思います。@アダムアーマー、これについての洞察を共有できる可能性はありますか?
mvexel

4
@mvexelこのwiki記事をご覧ください。マテリアライズドビューの基本と、PostgreSQLでそれらを実装する方法について詳しく説明しています。
アダムアーマー

5

hstore列のインデックスを作成してみてください。

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

次に、?演算子を使用してクエリをその行のみに制限します。

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

ありがとう!既にそのインデックスを作成しましたが、使用していませんでした。特定の操作を高速化するだけです。PostgreSQL 8.3(私が使用している)では、@>と?のみです。、9.0では@>、?、?&および?|です。
mvexel

1
記録の場合、?演算子を使用したクエリは、クエリの88秒と比較して48秒かかりました(昨日は72秒だったことがわかりません。クエリを実行しているときに、マシンが何か複雑な処理をしていたのかもしれません)。したがって、私が探しているパフォーマンスではありませんが、hstoreカラムでGISTインデックスがどのように動作するかをより深く理解しました。必要なパフォーマンスを得るには、マテリアライズドビューを作成する他のソリューションを使用する必要があります。
mvexel

3

st_withinおよび_st_within関数は、速度が不明です。&&演算子は、ジオメトリではなくbboxをチェックするので役立ちます。

次のことを試してみてください。

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

パフォーマンスのヒントの詳細については、http//postgis.refractions.net/docs/ch06.htmlをご覧ください。


2

クエリの問題はtags->'man_made'='surveillance'句です。これにより、Postgresはタグhstoreを強制的に展開し、インデックスの使用を許可しません。これを使用して書き換える場合@>(含む)と、インデックスの使用が許可されます。

四角形をクエリしているため&&、ST_Withinの代わりに使用できます。これは、ST_Withinが評価するのにそれほど複雑ではなく、ST_Withinが暗黙的に&&チェックを。

さらに速度を上げるには、GISTインデックスの代わりにタグでGINインデックスを使用します。GINインデックスは構築に時間がかかりますが、高速です。

クエリ全体は

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

特定のタグを頻繁にクエリすることがわかっている場合は、で部分インデックスを作成できますCREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);

これにより、WHERE条件でtags->'man_made'='surveillance'インデックスを使用できるようになります。残念ながら、そのインデックスは@>クエリを支援できず、GINまたはGISTインデックスはtags->'foo'クエリを支援できないため、クエリをお持ちのインデックスに一致させる必要があります。


使用するアドバイスtags @>hstore()により、クエリが大幅に改善されました。
alphabetasoup

1

代わりにこれを試してください:

SELECT n.geom、n.tags、n.tstamp、u.name AS AS IN INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> 'man_made => surveillance' :: hstore AND ST_Within(geom 、ST_GeomFromText( 'POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))'、4326));

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.