Chave / valor Hstore combinado e consulta espacial muito lentos para lidar com extrações maiores do OSM

13

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;
Alf Kortig
fonte
1
Você tem índice espacial em bavaria.nodes?
precisa saber é o seguinte
sim, eu editei a pergunta e forneceu informações sobre o índice em nós e o plano de consulta
Alf Kortig
3
Duas opções. 1 - adicione um índice para as tags hstore. 2 - extraia as tags que você está usando para sua consulta ( boundarye admin_level) em colunas extras na tabela e use-as diretamente.
precisa saber é o seguinte
Veja edit (3): dois índices foram adicionados, mas não houve alteração no plano de consulta nem no tempo de execução.
Alf Kortig
Após alguns testes, não tenho mais certeza se criei os índices corretos em (3). Até agora, consegui criar um índice para o -> e? operadores hstore. No entanto, estou usando @> na minha consulta
Alf Kortig

Respostas:

5

A melhor maneira de indexar tags hstore é usar índices GIN ou GIST, que, a partir dos documentos , suportam @>,?,? & E | | operadores , isto é, procura chaves e pares chave / valor. A abordagem de usar uma função para extrair as tags para um índice da árvore B é razoável, mas como você também está checando pares específicos de chave / valor, o analisador escolheu uma varredura completa da tabela.

Não tenho acesso ao bavaria.relpolygons, mas com base em uma consulta semelhante para o OSM UK sobre limites de velocidade e tags de rodovia, recebo isso para minha explicação na consulta a seguir:

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 mostra uma varredura direta de índice (usando o índice de essência), o que para uma tabela com 10 milhões de linhas é encorajador. O índice foi criado com o simples:

CREATE INDEX ix_ways_tags_gist ON ways USING gist (tags);

Embora eu não possa verificar sua condição espacial, acho que é menos seletivo do que

WHERE relpoly.tags @> '"limite" => "administrativo", "admin_level" => "6"' :: hstore.

e, portanto, seria usado apenas para uma condição de verificação novamente.

Há também essa ótima resposta SO sobre a diferença entre os índices GIN e GIST . A conclusão geral é que os índices GIN, embora sejam maiores e mais lentos de compilar, são muito mais rápidos em problemas de recuperação de texto.

Lamento responder tão tarde, mas recentemente trabalho em semelhante OSM e hstore e descobri que não apenas uma vez estrelou esta pergunta, mas agora pude responder: D.

John Powell
fonte