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.