Estou tentando calcular algumas estatísticas para dados OSM usando o PostgreSQL 9.3.5 e o PostGIS 2.1.4. Comecei com um pequeno extrato de bavaria que baixei da Geofabrik. O esquema db é o esquema normal da API 0.6, os dados foram importados por meio da abordagem de despejo para o Postgres (usando os scripts pgsnapshot_schema_0.6 * .sql que vêm com osmose). ANALISAR O VÁCUO também foi realizado.
A única coisa personalizada que estou usando é uma tabela de polígonos que contém multipolígonos para todas as relações administrativas de limite. A geometria do polígono não foi simplificada de forma alguma.
O que estou tentando agora é contar todos os nós que estão dentro dos limites admin = 6 da bavaria. Aqui está minha 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;
O tempo de execução dessa consulta é terrível porque o Postgres está fazendo uma junção de loop aninhada e varre todos os nós para todos os limites admin = 6. Para sua informação, a bavaria é dividida em 98 admin = 6 polígonos e existem cerca de 30 milhões de nós no extrato da bavaria.
É possível evitar essa execução subótima de consulta e informar ao Postgres que ele deve verificar todos os nós apenas uma vez (por exemplo, incrementando um contador para o polígono correspondente no conjunto de resultados ou usando dicas)?
Editar:
1) existe um índice espacial nos nós da bavaria:
CREATE INDEX idx_nodes_geom ON bavaria.nodes USING gist (geom);
2) o plano de consulta fica assim:
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)
Criei os dois índices a seguir, mas o plano de consulta (e o tempo de execução) não foram alterados
CREATE INDEX relpolygons_tags_boundary on bavaria.relpolygons( (tags->'boundary') );
CREATE INDEX relpolygons_tags_admin on bavaria.relpolygons( (tags->'admin_level') );
ANALYZE bavaria.relpolygons;
boundary
e admin_level
) em colunas extras na tabela e use-as diretamente.