Om du kan begränsa det maximala avståndet mellan dina städer och din lokala position, dra fördel av det faktum att en minuts latitud (nord - syd) är en sjömil.
Sätt ett index på din latitudtabell.
Gör dig själv en haversine(lat1, lat2, long1, long2, unit) lagrad funktion från haversineformeln som visas i din fråga. Se nedan
Gör sedan detta, givet mylatitude, mylongitud och mykm.
SELECT *
from cities a
where :mylatitude >= a.latitude - :mykm/111.12
and :mylatitude <= a.latitude + :mykm/111.12
and haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') <= :mykm
order by haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM')
Detta kommer att använda en latitudgränsruta för att grovt utesluta städer som är för långt borta från din punkt. Din DBMS kommer att använda en skanning av indexintervall på ditt latitudindex för att snabbt välja ut de rader i din stadstabell som är värda att överväga. Sedan kör den din haversine-funktion, den med all sinus- och cosinus-matematik, bara på dessa rader.
Jag föreslår latitud eftersom longitudavståndet på marken varierar med latitud.
Observera att detta är grovt. Det är bra för en butikssökare, men använd det inte om du är civilingenjör – jorden har en elliptisk form och detta förutsätter att den är cirkulär.
(Förlåt för det magiska talet 111,12. Det är antalet km i en latitud, det vill säga i sextio sjömil.)
Se här för en fungerande distansfunktion.
Varför ger den här MySQL-lagrade funktionen andra resultat än att göra beräkningen i frågan?