Die Kombination aus Hstore-Schlüssel / Wert und räumlicher Abfrage ist zu langsam, um größere OSM-Extrakte verarbeiten zu können

13

Ich versuche, mit PostgreSQL 9.3.5 und PostGIS 2.1.4 einige Statistiken für OSM-Daten zu berechnen. Ich habe mit einem kleinen Bayern-Extrakt angefangen, den ich von der Geofabrik heruntergeladen habe. Das DB-Schema ist das normale API 0.6-Schema. Die Daten wurden über den Dump-Ansatz in Postgres importiert (mithilfe der mit Osmose gelieferten Skripte pgsnapshot_schema_0.6 * .sql). ANALYSE VACUUM wurde ebenfalls durchgeführt.

Ich verwende nur eine Polygontabelle, die Multipolygone für alle administrativen Grenzbeziehungen enthält. Die Polygongeometrie wurde in keiner Weise vereinfacht.

Ich versuche jetzt, alle Knoten zu zählen, die innerhalb der Grenzen von admin = 6 von Bayern liegen. Hier ist meine SQL-Abfrage:

SELECT relpoly.id, count(node) 
FROM bavaria.relpolygons relpoly, bavaria.nodes node
WHERE relpoly.tags @> '"boundary"=>"administrative","admin_level"=>"6"'::hstore 
AND ST_Intersects(relpoly.geom, node.geom)
GROUP BY relpoly.id;

Die Laufzeit dieser Abfrage ist furchtbar, da Postgres einen Join mit verschachtelten Schleifen ausführt und alle Knoten nach jeder Grenze von admin = 6 durchsucht. Zu Ihrer Information, Bayern ist in 98 Admin = 6 Polygone unterteilt und der Bayern-Extrakt enthält ungefähr 30 Millionen Knoten.

Ist es möglich, diese suboptimale Abfrageausführung zu vermeiden und Postgres mitzuteilen, dass alle Knoten nur einmal durchsucht werden sollen (z. B. durch Inkrementieren eines Zählers für das entsprechende Polygon in der Ergebnismenge oder durch Verwenden von Hinweisen)?

Bearbeiten:

1) Auf den Bayernknoten existiert ein räumlicher Index:

CREATE INDEX idx_nodes_geom ON bavaria.nodes USING gist (geom);

2) Der Abfrageplan sieht folgendermaßen aus:

HashAggregate  (cost=284908.49..284908.75 rows=26 width=103)
  ->  Nested Loop  (cost=111.27..283900.80 rows=201537 width=103)
        ->  Bitmap Heap Scan on relpolygons relpoly  (cost=4.48..102.29 rows=26 width=5886)
              Recheck Cond: (tags @> '"boundary"=>"administrative", "admin_level"=>"6"'::hstore)
              ->  Bitmap Index Scan on relpolygons_geom_tags  (cost=0.00..4.47 rows=26 width=0)
                    Index Cond: (tags @> '"boundary"=>"administrative", "admin_level"=>"6"'::hstore)
        ->  Bitmap Heap Scan on nodes node  (cost=106.79..10905.50 rows=983 width=127)
              Recheck Cond: (relpoly.geom && geom)
              Filter: _st_intersects(relpoly.geom, geom)
              ->  Bitmap Index Scan on idx_nodes_geom  (cost=0.00..106.55 rows=2950 width=0)
                    Index Cond: (relpoly.geom && geom)

3)

Ich habe die folgenden zwei Indizes erstellt, aber der Abfrageplan (und die Laufzeit) haben sich nicht geändert

CREATE INDEX relpolygons_tags_boundary on bavaria.relpolygons( (tags->'boundary') );
CREATE INDEX relpolygons_tags_admin on bavaria.relpolygons( (tags->'admin_level') );
ANALYZE bavaria.relpolygons;
Alf Kortig
quelle
1
Haben Sie einen räumlichen Index in bavaria.nodes?
user30184
Ja, ich habe die Frage bearbeitet und Informationen über den Index für Knoten und den Abfrageplan bereitgestellt
Alf Kortig
3
Zwei Optionen. 1 - Fügen Sie einen Index für die Hstore-Tags hinzu. 2 - Extrahieren Sie die Tags, die Sie für Ihre Abfrage ( boundaryund admin_level) verwenden, in zusätzliche Spalten in der Tabelle und verwenden Sie diese direkt.
BradHards
Siehe edit (3): Es wurden zwei Indizes hinzugefügt, aber weder am Abfrageplan noch an der Laufzeit wurden Änderungen vorgenommen.
Alf Kortig
Nach einigen Tests bin ich mir nicht mehr sicher, ob ich die richtigen Indizes in (3) erstellt habe. Bisher habe ich es geschafft, einen Index für die -> und? hstore-Betreiber. Ich verwende jedoch @> in meiner Abfrage
Alf Kortig

Antworten:

5

Der beste Weg, um hstore-Tags zu indizieren, ist die Verwendung von GIN- oder GIST-Indizes, die in den Dokumenten die Zeichen @>,?,? & Und? | Unterstützen Operatoren suchen also nach Schlüsseln und Schlüssel / Wert-Paaren. Die Verwendung einer Funktion zum Extrahieren der Tags für einen B-Tree-Index ist sinnvoll. Da Sie jedoch auch nach bestimmten Schlüssel / Wert-Paaren suchen, hat der Analysator einen vollständigen Tabellenscan ausgewählt.

Ich habe keinen Zugriff auf bavaria.relpolygons, aber basierend auf einer ähnlichen Abfrage für OSM UK zu Geschwindigkeitsbegrenzungen und Autobahn-Tags erhalte ich diese für meine Erklärung zu der folgenden Abfrage:

SELECT count(*) 
 FROM ways 
WHERE tags @> 'highway=>motorway'::hstore 
 AND tags @> 'maxspeed=>"50 mph"'::hstore;


Aggregate  (cost=48.66..48.67 rows=1 width=0)
    ->  Index Scan using ix_ways_tags_gist on ways  (cost=0.42..48.64 rows=11 width=0)
     Index Cond: ((tags @> '"highway"=>"motorway"'::hstore) AND (tags @> '"maxspeed"=>"50 mph"'::hstore))

Dies zeigt einen direkten Index-Scan (unter Verwendung des Hauptindex), der für eine Tabelle mit 10 Millionen Zeilen ermutigend ist. Der Index wurde mit dem einfachen erstellt:

CREATE INDEX ix_ways_tags_gist ON ways USING gist (tags);

Ich kann Ihren räumlichen Zustand zwar nicht überprüfen, schätze aber, dass er weniger selektiv ist als

WHERE relpoly.tags @> '"border" => "administrative", "admin_level" => "6"' :: hstore.

und würde daher nur für eine erneute Prüfung verwendet werden.

Es gibt auch diese großartige SO-Antwort auf den Unterschied zwischen GIN- und GIST-Indizes . Die allgemeine Erkenntnis ist, dass GIN-Indizes zwar größer und langsamer zu erstellen sind, jedoch bei Problemen mit der Texterfassung viel schneller sind.

Es tut mir leid, dass ich so spät geantwortet habe, aber ich habe kürzlich ähnliche Arbeiten an OSM und hstore durchgeführt und festgestellt, dass ich diese Frage nicht nur einmal gestellt habe, sondern jetzt beantworten konnte: D.

John Powell
quelle