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?
Antworten:
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.
quelle
Sie können versuchen, einen Index für Ihre hstore-Spalte zu erstellen.
Verwenden Sie dann den
?
Operator, um die Abfrage auf nur diese Zeilen zu beschränken:quelle
?
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.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:
Weitere Leistungstipps finden Sie unter http://postgis.refractions.net/docs/ch06.html
quelle
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 kanntags->'foo'
Abfragen nicht helfen , daher müssen Sie die Abfragen mit den von Ihnen verwendeten Indizes abgleichen.quelle
tags @>hstore()
meine Anfrage massiv verbessert, danke.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));
quelle