D'abord quelques commentaires...
J'ai vu des dizaines (pas des millions) d'implémentations ici et sur d'autres forums ; le vôtre est meilleur que la plupart.
Selon une source de données (que j'ai téléchargée), il y a environ 3,2 millions de villes dans le monde.
Pour des raisons de performances, vous devez éviter de vérifier toutes les lignes 3M. Vous avez pris un bon départ avec la boîte englobante croissante. Notez que vous devriez avoir
INDEX(lat, lon),
INDEX(lon, lat)
L'optimiseur choisira entre celles-ci et la première requête (avec le COUNT(*)
) considérera cela comme "couvrant". Ce sera une bande autour du globe ou un biseau; une nette amélioration par rapport aux rangées de 3M. La pire latitude (+34 degrés) compte 96 000 villes. (1 degré =69 miles / 111 km.) Pour un dixième de degré, 34,4 est le pire, avec 10 000 villes.
(Oui, j'aime ce genre de puzzle de données.)
Et, je vois que vous gérez la ligne de date et les pôles. Je ne pense pas que vous puissiez vous améliorer en les ayant comme cas particulier.
(Je n'ai jeté qu'un coup d'œil aux formules et aux constantes.)
Aide à l'indexation Geohash et Z-order. Mais ils ont un hic dans la mesure où vous devez vérifier jusqu'à 4 zones autour de la cible - C'est comme ne pas réaliser que les nombres entiers 199999 et 200000 sont vraiment proches l'un de l'autre, bien que le premier chiffre de chacun soit différent.
"L'utilisateur passe par le code postal ou le nom de la ville" - c'est une requête ponctuelle dans l'une des deux tables simples. (Sauf qu'il peut y avoir des doublons -- plus de 320 chacun pour "san jose" et "san antonio". Assez loin dans la liste se trouve le premier nom non espagnol :"victoria", avec seulement 144 villes.)
Deuxièmement, ma mise en œuvre... (Il a quelques similitudes avec le vôtre.)
http://mysql.rjweb.org/doc.php/latlng
Cela améliore les performances en utilisant le PARTITIONing
à garder la boîte englobante à peu près un carré, au lieu d'une bande ou d'un coin. Si vous recherchez les 5 plus proches, mon algorithme touchera rarement plus de quelques dizaines de lignes, et ces lignes seront "regroupées" dans un petit nombre de blocs, ce qui maintiendra le nombre d'accès au disque très bas.
Une chose essentielle dans ma conception est d'avoir toutes les colonnes nécessaires dans une seule table. Une fois que vous avez trouvé les 5 les plus proches, vous pouvez vous diriger vers d'autres tables pour obtenir des choses annexes (numéro de téléphone, etc.).
Quant aux codes postaux, transformez-les en lat/lon avant de lancer la recherche des 5 plus proches.
Une jointure à l'intérieur de l'algorithme est très susceptible de détruire les performances.