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;
fuente
boundary
yadmin_level
) en columnas adicionales en la tabla y úselas directamente.Respuestas:
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:
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:
Si bien no puedo verificar su condición espacial, supongo que es menos selectiva que
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.
fuente