Beschleunigung der OpenStreetMap PostGIS-Abfrage

12

Ich habe OpenStreetMap-Daten für die Niederlande mit dem Osmoseschema in eine PostGIS-Datenbank (PostgreSQL 8.3 / PostGIS 1.3.3) geladen . Dies bedeutet, dass alle Tags in einem Speicherfeld gespeichert werden. Zusätzlich zum GIST-Index, den die Osmose für das Geometriefeld erstellt, habe ich einen zusätzlichen GIST-Index für das Tags-Feld erstellt.

Wenn ich versuche, sowohl eine räumliche Einschränkung als auch eine Einschränkung für das Tags-Feld zu verwenden, stelle ich fest, dass es langsamer ist, als ich es gerne hätte. Eine Abfrage wie diese:

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

Es dauert 22 Sekunden, um 78 Datensätze zurückzugeben.

In dieser Tabelle befinden sich rund 53 Millionen Datensätze.

Gibt es eine Möglichkeit, dies erheblich zu beschleunigen? Ich habe gehört, dass hstore in PostgreSQL 9 deutlich besser implementiert ist. Würde ein Upgrade helfen?

mvexel
quelle
Da dies eine datenbankorientierte Frage zu sein scheint, empfehle
jcolebrand 24.03.11
Update für 2015 - PostGIS hat die Leistung erheblich verbessert, seitdem diese Frage gestellt wurde. Berücksichtigen Sie dies ebenso wie das PostgreSQL-Upgrade.
Toby Speight

Antworten:

5

Eine Methode wäre, die Tags abzufragen, an denen Sie interessiert sind, und diese Datensätze in einer neuen Tabelle abzulegen. Dann müssen Sie statt aller 53 Millionen Datensätze nur die neue Tabelle abfragen. Wenn Sie versuchen, Ihre Datenbank auf dem neuesten Stand zu halten, kann diese Abfrage jedes Mal ausgeführt werden, wenn Sie neue Daten von OSM erhalten.

jvangeld
quelle
2
Anstatt eine neue Tabelle zu erstellen, sollten Sie stattdessen eine VIEW erstellen. Auf diese Weise wird die Abfrage live mit Ihren ursprünglichen Quelldaten verknüpft, ohne dass die Daten wörtlich dupliziert werden.
RyanKDalton
7
Eine Ansicht verbessert nicht unbedingt die Abfrageleistung, es sei denn, es handelt sich um eine materialisierte Ansicht oder eine gleichwertige Ansicht (siehe SO-Frage zu diesem Thema). Ich glaube nicht, dass Postgresql materialisierte Ansichten direkt unterstützt, aber sie können mithilfe von Triggern implementiert werden.
Adam Armour
2
Dies ist die Problemumgehung, die ich derzeit verwende. Nach einer Aktualisierung der Osmosetabellen erstelle ich einige Tabellen neu, die für die Abfragen optimiert sind, die ich ausführen möchte. Ich denke nur, dass es einen besseren Weg geben muss. Das Thema Auslöser fasziniert mich und wie Sie damit Materialansichten implementieren können. @Adam Armor, haben Sie eine Chance, einen Einblick darüber zu erhalten?
MVEXEL
4
@mvexel Schauen Sie sich diesen Wiki-Artikel an , der die Grundlagen materialisierter Ansichten und deren Implementierung in PostgreSQL behandelt.
Adam Armour
5

Sie können versuchen, einen Index für Ihre hstore-Spalte zu erstellen.

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

Verwenden Sie dann den ?Operator, um die Abfrage auf nur diese Zeilen zu beschränken:

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));
olt
quelle
Vielen Dank! Ich habe diesen Index bereits erstellt, nur habe ich ihn nicht verwendet. Dies beschleunigt nur bestimmte Vorgänge. In PostgreSQL 8.3 (das ich verwende) ist es nur @> und? , in 9.0 ist es @>,?,? & und? | .
MVEXEL
1
Für die Aufzeichnung hat die Abfrage mit dem ?Operator 48 Sekunden gedauert, verglichen mit 88 Sekunden für meine Abfrage (ich weiß nicht, wie ich gestern 72 Sekunden bekommen habe, vielleicht hat die Maschine diesmal etwas Kompliziertes getan, während ich die Abfragen durchgeführt habe). Also immer noch nicht die Leistung, die ich suche, aber ich habe ein tieferes Verständnis dafür gewonnen, wie die GIST-Indizes auf Hstore-Spalten funktionieren. Ich werde mich noch mit der anderen Lösung beschäftigen müssen, eine materialisierte Ansicht zu erstellen, um die gewünschte Leistung zu erzielen.
MVEXEL
3

Die Funktionen st_within und _st_within sind für ihre Geschwindigkeit nicht bekannt. Der Operator && kann hilfreich sein, da er bbox anstelle von geometry überprüft

Sie könnten Folgendes versuchen:

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

Weitere Leistungstipps finden Sie unter http://postgis.refractions.net/docs/ch06.html

milovanderlinden
quelle
2

Das Problem mit Ihrer Abfrage ist die tags->'man_made'='surveillance'Klausel. Dies zwingt Postgres, den Tags-Speicher zu erweitern, und erlaubt es Postgres nicht, den Index zu verwenden. Wenn Sie dies mit @>(enthält) umschreiben , kann der Index verwendet werden.

Da Sie ein Rechteck abfragen, können Sie &&anstelle von ST_Within verwenden. Dies hat einen kleinen Vorteil, da ST_Within nicht so kompliziert auszuwerten ist und ST_Within implizit eine &&Überprüfung durchführt.

Eine zusätzliche Geschwindigkeitssteigerung wäre die Verwendung eines GIN-Index für Tags anstelle eines GIST-Index. Die Erstellung von GIN-Indizes dauert länger, ist jedoch schneller.

Die gesamte Abfrage wäre

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

Wenn Sie wissen, dass Sie ein bestimmtes Tag häufig abfragen, können Sie einen Teilindex erstellen CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Dadurch kann die WHERE-Bedingung tags->'man_made'='surveillance'den Index verwenden. Leider kann dieser Index @>Abfragen nicht helfen, und der GIN- oder GIST-Index kann tags->'foo'Abfragen nicht helfen , daher müssen Sie die Abfragen mit den von Ihnen verwendeten Indizes abgleichen.

Paul Norman
quelle
Der Ratschlag zur Verwendung hat tags @>hstore()meine Anfrage massiv verbessert, danke.
Alphabetasoup
1

Versuchen Sie dies stattdessen:

SELECT n.geom, n.tags, n.tstamp, u.name FROM node AS n INNER JOIN user AS n.user_id = u.id WHERE tags @> 'man_made => monitoring' :: 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));

LR1234567
quelle