Niestety ST_Distance() < threshold
nie jest szargable
kryterium wyszukiwania. Aby spełnić to zapytanie, MySQL musi obliczyć wartość funkcji dla każdego wiersza w tabeli, a następnie porównać ją z progiem. Musi więc wykonać pełne skanowanie tabeli (lub może pełne skanowanie indeksu).
Aby wykorzystać indeks do przyspieszenia tego zapytania, będziesz potrzebować kryterium ograniczającego. Zapytanie jest dużo bardziej rozbudowane, ale także dużo szybsze. Zakładając, że punkty x/y w geometrii reprezentują szerokość/długość geograficzną w stopniach, zapytanie to może wyglądać tak:
set @latpoint = 38.0234332;
set @lngpoint = -94.0724223;
set @r = 10.0; /* ten mile radius */
set @units=69.0; /* 69 statute miles per degree */
SELECT AsText(geo)
FROM markers
WHERE MbrContains(GeomFromText(
CONCAT('LINESTRING(', @latpoint-(@r/@units),' ',
@lngpoint-(@r /(@units* COS(RADIANS(@latpoint)))),
',',
@latpoint+(@r/@units) ,' ',
@lngpoint+(@r /(@units * COS(RADIANS(@latpoint)))),
')')),
geo)
Jak to działa? Po pierwsze, MbrContains( związany, przedmiot) funkcja jest sargable . Po drugie, duży brzydki element concat tworzy ukośną linię od południowego zachodu do północno-wschodniego narożnika prostokąta ograniczającego. Przy użyciu punktu danych i promienia dziesięciu mil wygląda to tak.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
Kiedy używasz GeomFromText()
renderowanie tej ukośnej linii w pierwszym argumencie MbrContains()
służy jako prostokąt graniczny. MbrContains()
może następnie wykorzystać sprytny indeks geometrii drzewa czworokątnego.
Po trzecie, ST_Distance()
, w MySQL, nie obsługuje obliczeń szerokości i długości geograficznej po wielkim okręgu. (PostgreSQL
ma bardziej wszechstronne rozszerzenie GIS
.) MySQL jest tak głupi jak klapa w flatland. Zakłada, że twoje punkty w twoich obiektach geometrycznych są reprezentowane w geometrii płaskiej. Więc ST_Distance() < 10.0
z punktami lng/lat robi coś dziwnego.
Jest jeden błąd w wynikach generowanych przez to zapytanie; zwraca wszystkie punkty w obwiedni, a nie tylko w określonym promieniu. Można to rozwiązać za pomocą oddzielnego obliczenia odległości. Opisałem to wszystko szczegółowo tutaj .
Uwaga :Dla szerokości i długości geograficznej w rozdzielczości GPS, 32-bitowy FLOAT
dane mają wystarczającą precyzję. DOUBLE
jest to, czego używa rozszerzenie geograficzne MySQL. Kiedy pracujesz w stopniach, więcej niż pięć miejsc po przecinku przekracza dokładność GPS. DECIMAL()
nie jest idealnym typem danych dla współrzędnych lat/lng.