Helaas ST_Distance() < threshold
is geen sargable
zoekcriterium. Om aan deze query te voldoen, moet MySQL de waarde van de functie voor elke rij in de tabel berekenen en deze vervolgens vergelijken met de drempelwaarde. Het moet dus een volledige tabelscan doen (of misschien een volledige indexscan).
Als u een index wilt gebruiken om deze zoekopdracht te versnellen, hebt u een criterium voor een begrenzingsvak nodig. De query is een stuk uitgebreider, maar ook een stuk sneller. Ervan uitgaande dat uw x/y-punten in uw geometrie de lengte- en breedtegraad in graden vertegenwoordigen, kan die zoekopdracht er als volgt uitzien:
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)
Hoe werkt dit? Om te beginnen de MbrContains( gebonden,item) functie is sargable . Bovendien levert het grote lelijke concat-item een diagonale lijn op van de zuidwestelijke naar de noordoostelijke hoek van de begrenzende rechthoek. Als je je datapunt en een straal van tien mijl gebruikt, ziet het er zo uit.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
Wanneer u de GeomFromText()
. gebruikt weergave van die diagonale lijn in het eerste argument naar MbrContains()
het dient als een begrenzende rechthoek. MbrContains()
kan dan de handige quadtree-geometrie-index gebruiken.
Ten derde, ST_Distance()
, in MySQL, verwerkt geen berekeningen voor de breedte- en lengtegraad van grote cirkels. (PostgreSQL
heeft een uitgebreidere GIS-extensie
.) MySQL's is zo dom als een flapjack in flatland. Het gaat ervan uit dat uw punten in uw geometrische objecten worden weergegeven in vlakke geometrie. Dus ST_Distance() < 10.0
met lng/lat-punten doet iets vreemds.
Er is één fout in de resultaten die deze query genereert; het retourneert alle punten in het selectiekader, niet alleen binnen de opgegeven straal. Dat is op te lossen met een aparte afstandsberekening. Ik heb dit allemaal hier in detail opgeschreven .
Opmerking :Voor breedte- en lengtegraad met GPS-resolutie, 32-bits FLOAT
gegevens voldoende nauwkeurig zijn. DOUBLE
is wat de geo-extensie van MySQL gebruikt. Als u in graden werkt, ligt meer dan vijf plaatsen achter de komma buiten de nauwkeurigheid van GPS. DECIMAL()
is geen ideaal datatype voor lat/lng-coördinaten.