Acelerar las consultas OpenStreetMap PostGIS

12

Tengo datos de OpenStreetMap para los Países Bajos cargados en una base de datos PostGIS (PostgreSQL 8.3 / PostGIS 1.3.3) usando el esquema de ósmosis . Esto significa que todas las etiquetas se almacenan en un campo hstore . Además del índice GIST que crea la ósmosis en el campo de geometría, creé un índice GIST adicional en el campo de etiquetas.

Intentando consultar usando una restricción espacial y una restricción en el campo de etiquetas, encuentro que es más lento de lo que me gustaría. Una consulta como esta:

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

Tarda 22 segundos en devolver 78 registros.

Hay alrededor de 53 millones de registros en esta tabla.

¿Hay alguna manera de acelerar significativamente esto? He oído que hstore se implementa significativamente mejor en PostgreSQL 9, ¿ayudaría la actualización?

mvexel
fuente
Como esta parece ser una pregunta orientada a la base de datos, le animo a que pregunte en dba.stackexchange.com
jcolebrand el
Actualización para 2015: PostGIS ha realizado importantes mejoras de rendimiento desde que se hizo esta pregunta, así que considere eso, así como la actualización de PostgreSQL.
Toby Speight

Respuestas:

5

Un método sería consultar las etiquetas que le interesan y colocar esos registros en una nueva tabla. Luego, solo tendrá que consultar la nueva tabla en lugar de los 53 millones de registros. Si está intentando mantener actualizada su base de datos, puede hacer que se ejecute esta consulta cada vez que obtenga datos nuevos de OSM.

jvangeld
fuente
2
En lugar de crear una nueva tabla, puede considerar crear una VISTA en su lugar, de esa manera su "consulta" se vincula en vivo a sus datos de origen originales sin la duplicación literal de los datos.
RyanKDalton
77
Una vista no necesariamente mejorará el rendimiento de la consulta, a menos que sea una vista materializada o equivalente (consulte la pregunta SO sobre este tema). No creo que Postgresql admita vistas materializadas directamente, pero se pueden implementar mediante disparadores.
Adam Armor el
2
Esta es la solución que estoy usando actualmente. Después de una actualización de las tablas de ósmosis, vuelvo a crear algunas tablas que están optimizadas para las consultas que quiero ejecutar. Siento que tiene que haber una mejor manera. El tema de los desencadenantes me intriga, y cómo podría usarlos para implementar vistas materiales. @ Adam Armor, ¿hay alguna posibilidad de que puedas compartir alguna idea sobre esto?
mvexel
44
@mvexel Eche un vistazo a este artículo wiki , que cubre los conceptos básicos de las vistas materializadas y detalla cómo implementarlas en PostgreSQL.
Adam Armor el
5

Puede intentar crear un índice para su columna hstore,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

y luego use el ?operador para limitar la consulta solo a esas filas:

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));
olt
fuente
¡Gracias! Ya creé ese índice, solo que no lo estaba usando. Solo acelera ciertas operaciones. En PostgreSQL 8.3 (que estoy usando) es solo @> y? , en 9.0 es @>,?,? & y? | .
mvexel 23/03/11
1
Para el registro, la consulta con el ?operador tomó 48 segundos en comparación con 88 segundos para mi consulta (no sé cómo obtuve 72 segundos ayer, tal vez la máquina estaba haciendo algo complicado esta vez mientras realizaba las consultas). Entonces todavía no es el rendimiento que estoy buscando, pero obtuve una comprensión más profunda de cómo funcionan los índices GIST en las columnas de hstore. Todavía tendré que ir con la otra solución de crear una vista materializada para obtener el rendimiento que quiero.
mvexel
3

Las funciones st_within y _st_within no son conocidas por su velocidad. El operador && podría ayudar, ya que marcará bbox en lugar de geometría

Puede intentar lo siguiente:

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

Para obtener más consejos de rendimiento, consulte: http://postgis.refractions.net/docs/ch06.html

milovanderlinden
fuente
2

El problema con su consulta es la tags->'man_made'='surveillance'cláusula. Esto obliga a Postgres a expandir las etiquetas hstore y no le permite hacer uso del índice. Si reescribe esto usando @>(contiene), permitirá el uso del índice.

Debido a que está consultando un rectángulo, puede usarlo en &&lugar de ST_Within. Esto tendrá una pequeña ganancia, ya que ST_Within no es tan complicado de evaluar, y ST_Within implícitamente hace una &&comprobación.

Un aumento de velocidad adicional sería usar un índice GIN en las etiquetas en lugar de un índice GIST. Los índices GIN tardan más en construirse pero son más rápidos.

La consulta completa sería

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

Si sabe que va a consultar mucho una etiqueta en particular, puede crear un índice parcial con ella CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Esto permitirá que la condición WHERE tags->'man_made'='surveillance'use el índice. Desafortunadamente, ese índice no puede ayudar a las @>consultas y los índices GIN o GIST no pueden ayudar a las tags->'foo'consultas, por lo que debe hacer coincidir las consultas con los índices que tiene.

Paul Norman
fuente
El consejo de usar tags @>hstore()masivamente mejoró mi consulta, gracias.
alphabetasoup
1

intente esto en su lugar:

SELECCIONE n.geom, n.tags, n.tstamp, u.name DESDE los nodos COMO n INTERIOR ÚNASE a los usuarios AS u ON n.user_id = u.id DONDE etiquetas @> 'man_made => vigilancia' :: hstore Y 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));

LR1234567
fuente