Primeiro alguns comentários...
Eu vi dezenas (não milhões) de implementação aqui e em outros fóruns; a sua é melhor que a maioria.
De acordo com uma fonte de dados (que por acaso baixei), existem cerca de 3,2 milhões de cidades no mundo.
Para desempenho, você precisa evitar verificar todas as 3 milhões de linhas. Você começou bem com a caixa delimitadora em crescimento. Observe que você deve ter
INDEX(lat, lon),
INDEX(lon, lat)
O Otimizador escolherá entre eles e a primeira consulta (com o
COUNT(*)
) verá isso como 'cobrindo'. Será uma faixa ao redor do globo ou uma cunha; uma melhoria definitiva sobre 3M linhas. A pior latitude (+34 graus) tem 96 mil cidades. (1 grau =69 milhas / 111 km.) Para um décimo de grau, 34,4 é o pior, com 10 mil cidades. (Sim, eu gosto desse tipo de quebra-cabeça de dados.)
E, vejo que você lida com a linha de data e os pólos. Eu não acho que você pode melhorar em tê-los como um caso especial.
(Só dei uma olhada nas fórmulas e constantes.)
Ajuda de indexação Geohash e Z-order. Mas eles têm um problema em que você precisa checar até 4 áreas ao redor do alvo -- É como não perceber que os inteiros 199999 e 200000 estão muito próximos um do outro, apesar do primeiro dígito de cada um ser diferente.
"O usuário passa o código postal ou o nome da cidade" - essa é uma consulta pontual em uma das duas tabelas simples. (Exceto que pode haver dups - mais de 320 cada de "san jose" e "san antonio". Bem abaixo na lista está o primeiro nome não espanhol:"victoria", com apenas 144 cidades.)
Segundo, minha implementação... (Tem algumas semelhanças com o seu.)
http://mysql.rjweb.org/doc.php/latlng
Isso melhora o desempenho usando
PARTITIONing
para manter a caixa delimitadora em aproximadamente um quadrado, em vez de uma faixa ou cunha. Se você estiver procurando os 5 mais próximos, meu algoritmo raramente tocará mais do que algumas dúzias de linhas, e essas linhas serão 'agrupadas' em um pequeno número de blocos, mantendo assim o número de acertos de disco muito baixo. Uma coisa crítica no meu design é ter todas as colunas necessárias em uma tabela. Depois de encontrar os 5 mais próximos, você pode ir para outras mesas para pegar coisas auxiliares (número de telefone, etc).
Quanto aos CEPs, transforme-os em lat/lon antes de iniciar a busca pelos 5 mais próximos.
É muito provável que uma junção dentro do algoritmo destrua o desempenho.