Accelerare le query PostGIS di OpenStreetMap


12

Ho i dati OpenStreetMap per i Paesi Bassi caricati in un database PostGIS (PostgreSQL 8.3 / PostGIS 1.3.3) usando lo schema dell'osmosi . Ciò significa che tutti i tag sono memorizzati in un campo hstore . Oltre all'indice GIST che l'osmosi crea sul campo della geometria, ho creato un ulteriore indice GIST sul campo dei tag.

Cercando di eseguire una query utilizzando sia un vincolo spaziale che un vincolo sul campo dei tag, trovo che sia più lento di quanto vorrei. Una query come questa:

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

impiega 22 secondi per restituire 78 record.

Ci sono circa 53 milioni di record in questa tabella.

C'è un modo per accelerare significativamente questo? Ho sentito che hstore è implementato significativamente meglio in PostgreSQL 9, l'aggiornamento potrebbe aiutare?


Dal momento che questa sembra essere una domanda orientata al database, ti incoraggio a fare una domanda su dba.stackexchange.com
jcolebrand,

Aggiornamento per il 2015 - PostGIS ha apportato miglioramenti significativi alle prestazioni da quando è stata posta questa domanda, quindi considera questo oltre all'aggiornamento PostgreSQL.
Toby Speight,

Risposte:


5

Un metodo sarebbe quello di cercare i tag che ti interessano e posizionare quei record in una nuova tabella. Quindi dovrai solo eseguire una query sulla nuova tabella anziché su tutti i 53 milioni di record. Se si sta tentando di mantenere aggiornato il database, è possibile eseguire questa query ogni volta che si ottengono nuovi dati da OSM.


2
Invece di creare una nuova tabella, potresti prendere in considerazione la creazione di una VISTA, in questo modo la tua "query" è in diretta collegata ai tuoi dati di origine originali senza la duplicazione letterale dei dati.
RyanKDalton,

7
Una vista non migliorerà necessariamente le prestazioni della query, a meno che non sia una vista materializzata o equivalente (vedere la domanda SO su questo argomento). Non credo che Postgresql supporti direttamente le viste materializzate , ma possono essere implementate usando i trigger.
Adam Armor,

2
Questa è la soluzione alternativa che sto attualmente utilizzando. Dopo un aggiornamento delle tabelle di osmosi, ricrea alcune tabelle ottimizzate per le query che voglio eseguire. Sento solo che deve esserci un modo migliore. L'argomento dei trigger mi incuriosisce e come potresti usarli per implementare viste materiali. @Adam Armor, hai qualche possibilità di condividere qualche idea su questo?
mvexel,

4
@mvexel Dai un'occhiata a questo articolo wiki , che tratta le basi delle viste materializzate e spiega come implementarle in PostgreSQL.
Adam Armor,

5

Puoi provare a creare un indice per la colonna hstore,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

e quindi utilizzare l' ?operatore per limitare la query solo a quelle righe:

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

Grazie! Ho già creato quell'indice, solo che non lo stavo usando. Accelera solo alcune operazioni. In PostgreSQL 8.3 (che sto usando) sono solo @> e? , in 9.0 è @>,?,? & e? | .
mvexel,

1
Per la cronaca, la query che utilizzava l' ?operatore ha impiegato 48 secondi rispetto agli 88 secondi della mia query (non so come ho ottenuto 72 secondi ieri, forse la macchina stava facendo qualcosa di complicato questa volta mentre ho eseguito le query). Quindi non sono ancora le prestazioni che sto cercando, ma ho acquisito una comprensione più approfondita del funzionamento degli indici GIST su colonne hstore. Dovrò ancora andare con l'altra soluzione di creare una visione materializzata per ottenere le prestazioni che desidero.
mvexel,

3

Le funzioni st_within e _st_within non sono note per la loro velocità. L'operatore && potrebbe essere di aiuto in quanto selezionerà bbox anziché geometria

Potresti provare quanto segue:

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

Per ulteriori suggerimenti sulle prestazioni, consultare: http://postgis.refractions.net/docs/ch06.html


2

Il problema con la tua query è la tags->'man_made'='surveillance'clausola. In questo modo Postgres espande i tag hstore e non gli consente di utilizzare l'indice. Se lo riscrivi usando @>(contiene), consentirà l'utilizzo dell'indice.

Poiché stai interrogando un rettangolo, puoi usare &&invece di ST_Within. Ciò avrà un piccolo guadagno, poiché ST_Within non è così complicato da valutare e ST_Within fa implicitamente un &&controllo.

Un ulteriore aumento della velocità sarebbe quello di utilizzare un indice GIN sui tag anziché un indice GIST. Gli indici GIN richiedono più tempo per essere compilati ma sono più veloci.

L'intera query sarebbe

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

Se sai che eseguirai una query su un determinato tag, puoi creare un indice parziale con esso CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Ciò consentirà alla condizione WHERE tags->'man_made'='surveillance'di utilizzare l'indice. Sfortunatamente, quell'indice non può aiutare le @>query e gli indici GIN o GIST non possono aiutare le tags->'foo'query, quindi devi abbinare le query agli indici che hai.


Il consiglio di usare in modo tags @>hstore()massiccio la mia domanda, grazie.
alphabetasoup,

1

prova questo invece:

SELEZIONA n.geom, n.tags, n.tstamp, u.name DA nodi AS n INNER JOIN utenti AS u ON n.user_id = u.id DOVE tag @> 'man_made => sorveglianza' :: 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));

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.