Eu tenho 2 conjuntos de pontos em 2 tabelas separadas. A tabela_a obteve 100k pontos e a tabela_b obteve 300k pontos. Estou tentando encontrar os pontos mais próximos em relação a qualquer ponto da tabela_b que esteja a 50 metros da tabela_a. Depois disso, calcule a coluna de queda, agrupe-as pela tabela_a coluna a_id e retorne o valor mais alto.
Eu escrevi uma consulta a seguir que atende essa criteira
SELECT DISTINCT ON (a_id) *
FROM (
SELECT
table_b.b_id,
table_b.height - st_3ddistance(table_b.geom, table_a.geom) fall,
table_b.geom,
table_a.a_id
FROM table_a
INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;
Adicionei índices de geometria 3d:
CREATE INDEX table_a_geom ON table_a USING GIST (geom gist_geometry_ops_nd);
CREATE INDEX table_b_geom ON table_b USING GIST (geom gist_geometry_ops_nd);
No entanto, meu problema é que não consigo fazer a consulta para usá-los. A plaina de consulta continua escolhendo a varredura de sequência lenta. Executo alguns testes alterando _st_3ddwithin com st_3ddwithin , <<->> <50 , criando buffer de 50 me interceptando , st_3ddistance <50, mas sempre que o planejador está escolhendo a varredura de sequência. Existe uma maneira de usar índices com desempenho superior ou alterar a consulta para usar índices?
Meu plano de consulta:
Unique (cost=10462593.70..10473018.43 rows=1 width=144)
-> Sort (cost=10462593.70..10467806.06 rows=2084945 width=144)
Sort Key: table_a.nmbayuid, ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom))) DESC
-> Nested Loop (cost=0.00..10243762.28 rows=2084945 width=144)
Join Filter: (_st_dwithin(table_a.geom, table_b.geomgr, '50'::double precision) AND ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom)) >= '0'::double precision))
-> Seq Scan on table_b (cost=0.00..1459.47 rows=47147 width=96)
-> Materialize (cost=0.00..10.97 rows=398 width=56)
-> Seq Scan on table_a (cost=0.00..8.98 rows=398 width=56)
fonte
_ST
são funções internas chamadas pelo PostGIS após a filtragem com um índice. Se você chamá-los diretamente, o índice não será usado.Respostas:
Primeiramente, como foi observado nos comentários, o sublinhado principal antes da função ST, ou seja, _ST_3DWithin levará o índice a não ser usado. Não consigo encontrar nenhuma menção recente a isso, mas em documentos mais antigos, se você procurar, por exemplo, _ST_Intersects, ele afirma:
EDIT: Conforme esclarecido por @dbaston nos comentários, as funções com o sublinhado à esquerda são funções internas que não usam o índice quando chamadas e esse continua sendo o caso (embora seja difícil de encontrar nos documentos).
Sua consulta pode se beneficiar da sintaxe LATERAL JOIN, que se presta bem a problemas de k vizinho mais próximo (kNN) como este.
Isso permite encontrar as geometrias k mais próximas da tabela a (neste caso 1, devido ao LIMIT 1) à tabela b, ordenadas pela distância 3D entre elas. Ele é escrito usando LEFT JOIN, pois é possível que haja algumas geometrias na tabela a que não estejam a 50 metros da tabela b.
As consultas laterais permitem que você faça referência a colunas da cláusula FROM anterior, o que a torna mais poderosa do que as subconsultas padrão, consulte os documentos .
Não posso testar isso com seus dados, mas, quando executo consultas semelhantes, a instrução EXPLAIN indica o uso adequado do índice.
fonte
Este link para a documentação do PostGIS recomenda as seguintes etapas para garantir que os índices e o planejador de consultas sejam otimizados:
Verifique se as estatísticas são reunidas sobre o número e as distribuições de valores em uma tabela, para fornecer ao planejador de consultas melhores informações para tomar decisões sobre o uso do índice. ANÁLISE DE VÁCUO calculará ambos.
Se a aspiração não ajudar, você pode forçar temporariamente o planejador a usar as informações do índice usando o conjunto enable_seqscan como off; comando. Dessa forma, você pode verificar se o planejador é capaz de gerar um plano de consulta acelerada por índice para sua consulta. Você só deve usar este comando apenas para depuração: de um modo geral, o planejador sabe melhor do que você sobre quando usar índices. Depois de executar sua consulta, não se esqueça de ativar ENABLE_SEQSCAN novamente, para que outras consultas utilizem o planejador normalmente.
Se definir enable_seqscan como off; ajuda a executar sua consulta, é provável que seu Postgres provavelmente não esteja ajustado para o seu hardware. Se você achar que o planejador está errado quanto ao custo das varreduras seqüenciais versus indexadas, tente reduzir o valor de random_page_cost no postgresql.conf ou use set random_page_cost como 1.1 ;. O valor padrão para o parâmetro é 4, tente configurá-lo para 1 (no SSD) ou 2 (em discos magnéticos rápidos). Diminuir o valor torna o planejador mais inclinado a usar as verificações de índice.
Se definir enable_seqscan como off; não ajuda sua consulta, pode acontecer que você use uma construção que o Postgres ainda não consiga desembaraçar. Uma subconsulta com seleção embutida é um exemplo - você precisa reescrevê-la para que o planejador de formulários possa otimizar, por exemplo, uma JUNTA LATERAL.
Portanto, primeiro tente as etapas 1 a 3 antes de reescrever sua consulta para usar os índices. Se isso não funcionar, você pode tentar modificar a consulta.
Acredito (o melhor de minha capacidade de ativar o SQL sem executar o código) que a consulta abaixo retornará resultados idênticos aos seus, mas não sei se será mais eficiente.
fonte
Se você estiver usando o Postgres 10 (ou mais recente), recomendo fortemente que você carregue seus dados em tabelas paralelas.
Você provavelmente precisará gastar tempo ajustando-o (particionamento de dados e número de trabalhadores), mas acho que vale a pena. Teoricamente, o KNN é altamente paralelelizável, alcançando complexidades de tempo constantes, até O (1) se a quantidade de trabalhadores for igual ao número de elementos em que uma operação do KNN será calculada.
Algumas referências práticas sobre o carregamento dos dados e a execução das consultas são fornecidas aqui . Ele fornece alguns detalhes sobre a execução do plano (para forçar mais trabalhadores a serem acionados) aqui . É importante observar que os scripts paralelos envolvem muita coordenação de tarefas, para que o limite teórico extremo de fornecer a paralelização mais extrema não seja válido na prática, devido a redes e outras características de design de sistemas.
fonte