Wenn Sie die maximale Entfernung zwischen Ihren Städten und Ihrer lokalen Position begrenzen können, nutzen Sie die Tatsache, dass eine Breitenminute (Nord - Süd) einer Seemeile entspricht.
Fügen Sie Ihrer Breitengradtabelle einen Index hinzu.
Machen Sie sich aus der in Ihrer Frage gezeigten Haversine-Formel eine gespeicherte Haversine-Funktion (lat1, lat2, long1, long2, unit). Siehe unten
Tun Sie dies dann unter Berücksichtigung von mylatitude, mylongitude und 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')
Dadurch wird ein Breitengrad-Begrenzungsrahmen verwendet, um Städte grob auszuschließen, die zu weit von Ihrem Punkt entfernt sind. Ihr DBMS verwendet einen Indexbereichsscan für Ihren Breitengradindex, um schnell die Zeilen in Ihrer Städtetabelle auszuwählen, die eine Überlegung wert sind. Dann wird Ihre Haversine-Funktion, die mit allen Sinus- und Cosinus-Berechnungen, nur auf diesen Zeilen ausgeführt.
Ich schlage den Breitengrad vor, weil die Entfernung des Längengrads auf dem Boden mit dem Breitengrad variiert.
Beachten Sie, dass dies grob ist. Es ist in Ordnung für einen Ladenfinder, aber verwenden Sie es nicht, wenn Sie ein Bauingenieur sind - die Erde hat eine elliptische Form und dies nimmt an, dass sie kreisförmig ist.
(Entschuldigen Sie die magische Zahl 111,12. Das ist die Anzahl der Kilometer in einem Breitengrad, also in sechzig Seemeilen.)
Siehe hier für eine funktionierende Entfernungsfunktion.
Warum liefert diese gespeicherte MySQL-Funktion andere Ergebnisse als die Berechnung in der Abfrage?