Если вы можете ограничить максимальное расстояние между вашими городами и местным положением, воспользуйтесь тем, что одна минута широты (север - юг) составляет одну морскую милю.
Поместите индекс в вашу таблицу широт.
Создайте себе сохраненную функцию haversine (lat1, lat2, long1, long2, unit) из формулы haversine, показанной в вашем вопросе. Смотри ниже
Затем сделайте это, учитывая mylatitude, mylongitude и 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')
Это будет использовать ограничивающую рамку широты, чтобы грубо исключить города, которые находятся слишком далеко от вашей точки. Ваша СУБД будет использовать сканирование диапазона индекса в индексе широты, чтобы быстро выбрать строки в таблице городов, которые стоит рассмотреть. Затем он запустит вашу функцию haversine, со всеми математическими функциями синуса и косинуса, только в этих строках.
Я предлагаю широту, потому что расстояние долготы на земле зависит от широты.
Обратите внимание, это грубо. Это хорошо для магазина, но не используйте его, если вы инженер-строитель - земля имеет эллиптическую форму, и это предполагает, что она круглая.
(Извините за магическое число 111.12. Это количество километров в градусах широты, то есть в шестидесяти морских милях.)
См. Здесь для работоспособной функции расстояния.
Почему эта хранимая функция MySQL дает результаты, отличные от вычислений в запросе?