Eu tenho um conjunto de dados nacional de pontos de endereço (37 milhões) e um conjunto de dados poligonais de contornos de inundação (2 milhões) do tipo MultiPolygonZ, alguns dos polígonos são muito complexos, o máximo de ST_NPoints é de cerca de 200.000. Estou tentando identificar usando o PostGIS (2.18) quais pontos de endereço estão em um polígono de inundação e escrevê-los em uma nova tabela com identificação de endereço e detalhes de risco de inundação. Tentei de uma perspectiva de endereço (ST_Within), mas depois troquei isso a partir da perspectiva da área de inundação (ST_Contains), justificando que existem grandes áreas sem risco de inundação. Ambos os conjuntos de dados foram reprojetados para 4326 e as duas tabelas possuem um índice espacial. Minha consulta abaixo está em execução há 3 dias e não mostra sinais de conclusão tão cedo!
select a.id, f.risk_factor_1, f.risk_factor_2, f.risk_factor_3
into gb.addresses_with_flood_risk
from gb.flood_risk_areas f, gb.addresses a
where ST_Contains(f.the_geom, a.the_geom);
Existe uma maneira mais ideal de executar isso? Além disso, para consultas de longa execução desse tipo, qual é a melhor maneira de monitorar o progresso, além de observar a utilização de recursos e a pg_stat_activity?
Minha consulta original terminou em OK, embora por três dias, e me desviei de outros trabalhos, para que eu nunca dedicasse tempo à tentativa da solução. No entanto, eu apenas visitei isso novamente e trabalhei com as recomendações, até agora tão boas. Eu usei o seguinte:
- Criou uma grade de 50 km no Reino Unido usando a solução ST_FishNet sugerida aqui
- Defina o SRID da grade gerada como British National Grid e construa um índice espacial nela
- Recortei meus dados de inundação (MultiPolygon) usando ST_Intersection e ST_Intersects (só peguei aqui foi preciso usar ST_Force_2D no geom, pois shape2pgsql adicionou um índice Z
- Recortou meus dados de ponto usando a mesma grade
- Criamos índices na linha e índice col e espacial em cada uma das tabelas
Estou pronto para executar meu script agora, iterará nas linhas e colunas que preenchem os resultados em uma nova tabela até que eu cubra todo o país. Mas acabei de verificar meus dados de inundação e alguns dos maiores polígonos parecem ter sido perdidos na tradução! Esta é a minha consulta:
SELECT g.row, g.col, f.gid, f.objectid, f.prob_4band, ST_Intersection(ST_Force_2D(f.geom), g.geom) AS geom
INTO rofrse.tmp_flood_risk_grid
FROM rofrse.raw_flood_risk f, rofrse.gb_grid g
WHERE (ST_Intersects(ST_Force_2D(f.geom), g.geom));
Meus dados originais são assim:
No entanto, após o recorte, fica assim:
Este é um exemplo de um polígono "ausente":
fonte
Respostas:
Para responder à sua última pergunta primeiro, consulte esta postagemsobre a conveniência de poder monitorar o progresso das consultas. O problema é difícil e seria composto em uma consulta espacial, pois saber que 99% dos endereços já haviam sido varridos para contenção em um polígono de inundação, que você poderia obter do contador de loop na implementação da varredura de tabela subjacente, não necessariamente ajuda se o 1% final de endereços cruzar um polígono de inundação com mais pontos, enquanto os 99% anteriores cruzam alguma área minúscula. Essa é uma das razões pelas quais EXPLAIN às vezes pode ser inútil em termos espaciais, pois fornece uma indicação das linhas que serão verificadas, mas, por razões óbvias, não leva em conta a complexidade dos polígonos (e, portanto, uma grande proporção do tempo de execução) de quaisquer consultas de tipo de interseção / interseção.
Um segundo problema é que, se você olhar para algo como
você verá algo como, depois de perder muitos detalhes:
A condição final, &&, significa fazer uma verificação na caixa delimitadora, antes de fazer uma interseção mais precisa das geometrias reais. Isso é obviamente sensato e está no centro de como as R-Trees funcionam. No entanto, e eu também trabalhei com dados de inundação do Reino Unido no passado, por isso estou familiarizado com a estrutura dos dados, se os (Multi) polígonos forem muito extensos - esse problema é particularmente grave se um rio correr, digamos, 45 graus - você recebe enormes caixas delimitadoras, o que pode forçar um grande número de interseções em potencial a serem verificadas em polígonos muito complexos.
A única solução que consegui encontrar para o problema "minha consulta está em execução há 3 dias e não sei se estamos com 1% ou 99%" é usar uma espécie de divisão e conquista para manequins abordagem, com o que quero dizer, divida sua área em partes menores e execute-as separadamente, em um loop no plpgsql ou explicitamente no console. Isso tem a vantagem de cortar polígonos complexos em partes, o que significa que pontos subseqüentes nas verificações de polígonos estão trabalhando em polígonos menores e as caixas delimitadoras dos polígonos são muito menores.
Consegui executar consultas em um dia dividindo o Reino Unido em blocos de 50 km por 50 km, depois de matar uma consulta que estava em execução há mais de uma semana em todo o Reino Unido. Como um aparte, espero que sua consulta acima seja CREATE TABLE ou UPDATE e não apenas um SELECT. Quando você estiver atualizando uma tabela, endereços, com base em um polígono de inundação, será necessário varrer toda a tabela que está sendo atualizada, endereços de qualquer maneira, portanto, na verdade, ter um índice espacial nela não ajuda em nada.
EDIT: Com base em que uma imagem vale mais que mil palavras, aqui está uma imagem de alguns dados de inundação no Reino Unido. Há um multipolígono muito grande, cuja caixa delimitadora cobre toda a área; é fácil ver como, por exemplo, ao cruzar primeiro o polígono de inundação com a grade vermelha, o quadrado no canto sudoeste seria repentinamente testado contra um pequeno subconjunto do polígono.
fonte