Acelerando a consulta do OpenStreetMap PostGIS

12

Eu tenho dados do OpenStreetMap para a Holanda carregados em um banco de dados PostGIS (PostgreSQL 8.3 / PostGIS 1.3.3) usando o esquema de osmose . Isso significa que todas as tags são armazenadas em um campo hstore . Além do índice GIST que a osmose cria no campo geometria, criei um índice GIST adicional no campo tags.

Tentando consultar usando uma restrição espacial e uma restrição no campo tags, acho que é mais lento do que gostaria. Uma consulta como esta:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

leva 22 segundos para retornar 78 registros.

Existem cerca de 53 milhões de registros nesta tabela.

Existe uma maneira de acelerar significativamente isso? Ouvi dizer que o hstore é implementado significativamente melhor no PostgreSQL 9. A atualização ajudaria?

mvexel
fonte
Uma vez que esta parece ser uma questão de banco de dados orientado Encorajo-vos a perguntar sobre dba.stackexchange.com
jcolebrand
Atualização para 2015 - O PostGIS fez melhorias significativas no desempenho desde que essa pergunta foi feita, portanto, considere isso e a atualização do PostgreSQL.
Toby Speight

Respostas:

5

Um método seria consultar as tags de seu interesse e colocar esses registros em uma nova tabela. Então, você só precisará consultar a nova tabela em vez de todos os 53 milhões de registros. Se você está tentando manter seu banco de dados atualizado, essa consulta pode ser executada toda vez que você obtiver novos dados do OSM.

jvangeld
fonte
2
Em vez de criar uma nova tabela, considere criar uma VIEW, para que a "consulta" seja vinculada ao vivo aos dados de origem originais sem a duplicação literal dos dados.
RyanKDalton
7
Uma visão não melhorará necessariamente o desempenho da consulta, a menos que seja uma visão materializada ou equivalente (consulte a pergunta SO neste tópico). Não acredito que o Postgresql suporte diretamente visualizações materializadas , mas elas podem ser implementadas usando gatilhos.
Adam Armour
2
Esta é a solução alternativa que estou usando no momento. Após uma atualização nas tabelas de osmose, recrio algumas tabelas otimizadas para as consultas que desejo executar. Eu apenas sinto que tem que haver uma maneira melhor. O tópico dos gatilhos me intriga e como você pode usá-los para implementar visualizações de materiais. @ Adam Armour, alguma chance de você compartilhar algumas idéias sobre isso?
mvexel
4
@mvexel Dê uma olhada neste artigo da wiki , que aborda os conceitos básicos de visualizações materializadas e detalhes de como implementá-las no PostgreSQL.
22611 Adam Armour
5

Você pode tentar criar um índice para sua coluna hstore,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

e use o ?operador para limitar a consulta apenas a essas linhas:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));
olt
fonte
Obrigado! Eu já criei esse índice, só que não estava usando. Acelera apenas determinadas operações. No PostgreSQL 8.3 (que eu estou usando) são apenas @> e? , no 9.0 é @>,?,? & e | | .
mvexel
1
Para o registro, a consulta usando o ?operador levou 48 segundos em comparação com 88 segundos para a minha consulta (não sei como recebi 72 segundos ontem, talvez a máquina estivesse fazendo algo complicado dessa vez enquanto eu realizava as consultas). Portanto, ainda não o desempenho que estou procurando, mas adquiri uma compreensão mais profunda de como os índices GIST operam nas colunas hstore. Ainda terei que ir com a outra solução de criar uma visão materializada para obter o desempenho que desejo.
mvexel
3

As funções st_within e _st_within não são conhecidas por sua velocidade. O operador && pode ajudar, pois verifica a bbox em vez da geometria

Você pode tentar o seguinte:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

Para obter mais dicas de desempenho, verifique: http://postgis.refractions.net/docs/ch06.html

milovanderlinden
fonte
2

O problema com sua consulta é a tags->'man_made'='surveillance'cláusula Isso força o Postgres a expandir as tags hstore e não permite que ele faça uso do índice. Se você reescrever isso usando @>(contém), permitirá o uso do índice.

Como você está consultando um retângulo, pode usar em &&vez de ST_Within. Isso terá um pequeno ganho, pois o ST_Within não é tão complicado de avaliar e o ST_Within faz uma &&verificação implicitamente .

Um aumento de velocidade adicional seria usar um índice GIN em tags, em vez de um índice GIST. Os índices GIN levam mais tempo para criar, mas são mais rápidos.

Toda a consulta seria

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

Se você sabe que consultará muito uma determinada tag, poderá criar um índice parcial nela CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Isso permitirá que a condição WHERE tags->'man_made'='surveillance'use o índice. Infelizmente, esse índice não pode ajudar as @>consultas e os índices GIN ou GIST não podem ajudar as tags->'foo'consultas, portanto, você deve corresponder as consultas aos índices existentes.

Paul Norman
fonte
O conselho para usar tags @>hstore()maciçamente melhorou minha consulta, obrigado.
alphabetasoup
1

tente isso:

SELECT n.geom, n.tags, n.tstamp, u.name FROM nós COMO n INTERESSE ENTRE usuários COMO u ON n.user_id = u.id WHERE tags @> 'man_made => surveillance' :: hstore AND ST_Within (geom , ST_GeomFromText ('POLYGON ((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))', 4326));

LR1234567
fonte