Chiave / valore Hstore combinato e query spaziale troppo lenti per gestire estratti di OSM più grandi


13

Sto cercando di calcolare alcune statistiche per i dati OSM usando PostgreSQL 9.3.5 e PostGIS 2.1.4. Ho iniziato con un piccolo estratto bavarese che ho scaricato da Geofabrik. Lo schema db è il normale schema API 0.6, i dati sono stati importati tramite l'approccio dump in Postgres (usando gli script pgsnapshot_schema_0.6 * .sql forniti con l'osmosi). ANALYZE VACUUM è stato anche eseguito.

L'unica cosa su misura che sto usando è una tabella poligonale che contiene multipoligoni per tutte le relazioni amministrative di confine. La geometria poligonale non è stata semplificata in alcun modo.

Ciò che ora sto cercando di ottenere è contare tutti i nodi che si trovano all'interno dell'amministratore = 6 confini della Baviera. Ecco la mia query SQL:

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;

Il runtime di questa query è terribile perché Postgres sta eseguendo un join loop nidificato ed esegue la scansione di tutti i nodi per ogni limite admin = 6. Cordiali saluti, la Baviera è divisa in 98 admin = 6 poligoni e ci sono circa 30 milioni di nodi nell'estratto della Baviera.

È possibile evitare l'esecuzione di una query non ottimale e dire a Postgres che dovrebbe scansionare tutti i nodi una sola volta (ad esempio, incrementando un contatore per il poligono corrispondente nel set di risultati o usando i suggerimenti)?

Modificare:

1) esiste un indice spaziale sui nodi bavaresi:

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

2) il piano di query è simile al seguente:

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)

Ho creato i seguenti due indici, ma il piano di query (e il runtime) non sono cambiati

CREATE INDEX relpolygons_tags_boundary on bavaria.relpolygons( (tags->'boundary') );
CREATE INDEX relpolygons_tags_admin on bavaria.relpolygons( (tags->'admin_level') );
ANALYZE bavaria.relpolygons;

1
Hai un indice spaziale in bavaria.nodes?
user30184

sì, ho modificato la domanda e fornito informazioni sull'indice sui nodi e sul piano di query
Alf Kortig,

3
Due opzioni. 1 - aggiungi un indice per i tag hstore. 2 - estrai i tag che stai utilizzando per la tua query ( boundarye admin_level) in colonne extra sulla tabella e usali direttamente.
BradHards il

Vedi modifica (3): sono stati aggiunti due indici, ma non sono state apportate modifiche al piano di query né al runtime.
Alf Kortig,

Dopo alcuni test non sono più sicuro di aver creato gli indici corretti in (3). Finora sono riuscito a creare un indice per -> e? operatori hstore. Tuttavia, sto usando @> nella mia query
Alf Kortig il

Risposte:


5

Il modo migliore per indicizzare i tag hstore è utilizzare gli indici GIN o GIST, che dai documenti supportano @>,?,? & E? | gli operatori , ovvero ricerche su chiavi e coppie chiave / valore. L'approccio all'utilizzo di una funzione per estrarre i tag per un indice B-tree è ragionevole, ma poiché stai anche verificando specifiche coppie chiave / valore, l'analizzatore ha scelto una scansione completa della tabella.

Non ho accesso a bavaria.relpolygons, ma sulla base di una query simile per OSM UK su limiti di velocità e tag autostrada, ottengo questo per il mio spiegazione sulla seguente query:

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

che mostra una scansione diretta dell'indice (usando l'indice gist), che per una tabella con 10 milioni di righe è incoraggiante. L'indice è stato creato con il semplice:

CREATE INDEX ix_ways_tags_gist ON ways USING gist (tags);

Anche se non riesco a controllarti le condizioni spaziali, immagino che sia meno selettivo di

DOVE relpoly.tags @> '"boundary" => "amministrativo", "admin_level" => "6"' :: hstore.

e verrebbe quindi utilizzato solo per una condizione di ricontrollo.

C'è anche questa grande risposta SO sulla differenza tra gli indici GIN e GIST . La scoperta generale è che gli indici GIN, sebbene più grandi e più lenti da costruire, sono molto più veloci sui problemi di recupero del testo.

Mi dispiace rispondere così tardi, ma recentemente ho svolto un lavoro simile su OSM e hstore, e ho scoperto che non solo una volta ero protagonista di questa domanda, ma che ora potevo rispondere: D.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.