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;

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.