La clave / valor combinada de Hstore y la consulta espacial son demasiado lentas para manejar extractos OSM más grandes

13

Estoy tratando de calcular algunas estadísticas para datos OSM usando PostgreSQL 9.3.5 y PostGIS 2.1.4. Comencé con un pequeño extracto de baviera que descargué de Geofabrik. El esquema db es el esquema API 0.6 normal, los datos se importaron a través del enfoque de volcado en Postgres (utilizando los scripts pgsnapshot_schema_0.6 * .sql que vienen con osmosis). ANÁLISIS DE VACÍO también se realizó.

Lo único personalizado que estoy usando es una tabla de polígonos que contiene multipolígonos para todas las relaciones de límites administrativos. La geometría del polígono no se simplificó de ninguna manera.

Lo que ahora estoy tratando de lograr es contar todos los nodos que están dentro de los límites admin = 6 de bavaria. Aquí está mi consulta 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;

El tiempo de ejecución de esta consulta es terrible porque Postgres está haciendo una unión de bucle anidado y escanea todos los nodos para cada límite admin = 6. Para su información, Baviera se divide en 98 admin = 6 polígonos y hay alrededor de 30 millones de nodos en el extracto de Baviera.

¿Es posible evitar esta ejecución de consulta subóptima y decirle a Postgres que debe escanear todos los nodos solo una vez (por ejemplo, incrementando un contador para el polígono correspondiente en el conjunto de resultados o usando sugerencias)?

Editar:

1) existe un índice espacial en los nodos de baviera:

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

2) el plan de consulta se ve así:

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)

Creé los siguientes dos índices, pero el plan de consulta (y el tiempo de ejecución) no cambió

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
fuente
1
¿Tiene índice espacial en bavaria.nodes?
user30184
Sí,
edité
3
Dos opciones. 1: agregue un índice para las etiquetas hstore. 2: extraiga las etiquetas que está utilizando para su consulta ( boundaryy admin_level) en columnas adicionales en la tabla y úselas directamente.
BradHards
Ver edición (3): se agregaron dos índices, pero no hubo cambios en el plan de consulta ni en el tiempo de ejecución.
Alf Kortig
Después de algunas pruebas, ya no estoy seguro de si creé los índices correctos en (3). Hasta ahora, logré crear un índice para -> y? Operadores hstore. Sin embargo, estoy usando @> en mi consulta
Alf Kortig

Respuestas:

5

La mejor manera de indexar las etiquetas de hstore es usar índices GIN o GIST, que desde los documentos , admiten @>,?,? & Y? | operadores , es decir, busca claves y pares clave / valor. Su enfoque de usar una función para extraer las etiquetas para un índice de árbol B es razonable, pero debido a que también está buscando pares clave / valor específicos, el analizador ha elegido un escaneo completo de la tabla.

No tengo acceso a bavaria.relpolygons, pero en base a una consulta similar para OSM UK sobre límites de velocidad y etiquetas de carretera, obtengo esto para mi explicación en la siguiente consulta:

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

que muestra un escaneo de índice directo (usando el índice general), que para una tabla con 10 millones de filas es alentador. El índice fue creado con el simple:

CREATE INDEX ix_ways_tags_gist ON ways USING gist (tags);

Si bien no puedo verificar su condición espacial, supongo que es menos selectiva que

DONDE relpoly.tags @> '"boundary" => "Administrative", "admin_level" => "6"' :: hstore.

y, por lo tanto, solo se usaría para una condición de revisión.

También existe esta gran respuesta SO sobre la diferencia entre los índices GIN y GIST . El hallazgo general es que los índices GIN, aunque son más grandes y más lentos de construir, son mucho más rápidos en problemas de recuperación de texto.

Lamento responder tan tarde, pero recientemente he estado haciendo un trabajo similar en OSM y hstore, y descubrí que no solo destaqué esta pregunta una vez, sino que ahora podía responderla: D.

John Powell
fuente