Sfortunatamente ST_Distance() < threshold
non è un sargable
criterio di ricerca. Per soddisfare questa query, MySQL deve calcolare il valore della funzione per ogni riga della tabella e quindi confrontarlo con la soglia. Quindi deve eseguire una scansione completa della tabella (o forse una scansione completa dell'indice).
Per sfruttare un indice per velocizzare questa query, avrai bisogno di un criterio del riquadro di delimitazione. La query è molto più elaborata ma anche molto più veloce. Supponendo che i tuoi punti x/y nella tua geometria rappresentino latitudine/longitudine in gradi, la query potrebbe essere simile a questa:
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)
Come funziona? Per prima cosa, MbrContains( rilegato, oggetto) funzione è sargable . Per un'altra cosa, l'oggetto concat grande e brutto produce una linea diagonale da sud-ovest all'angolo nord-est del rettangolo di delimitazione. Usando il tuo punto dati e un raggio di dieci miglia sembra questo.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
Quando usi GeomFromText()
rendering di quella linea diagonale nel primo argomento in MbrContains()
funge da rettangolo di delimitazione. MbrContains()
può quindi sfruttare l'elegante indice di geometria quadtree.
In terzo luogo, ST_Distance()
, in MySQL, non gestisce i calcoli di latitudine e longitudine del cerchio grande. (PostgreSQL
ha un'estensione GIS
più completa .) MySQL è stupido come un flapjack in pianura. Presuppone che i tuoi punti nei tuoi oggetti geometrici siano rappresentati in geometria planare. Quindi ST_Distance() < 10.0
con punti lng/lat fa qualcosa di strano.
C'è un difetto nei risultati generati da questa query; restituisce tutti i punti nel riquadro di delimitazione, non solo all'interno del raggio specificato. Questo è risolvibile con un calcolo della distanza separato. Ho scritto tutto questo in dettaglio qui .
Nota :Per la latitudine e la longitudine con risoluzione GPS, FLOAT
a 32 bit i dati hanno una precisione sufficiente. DOUBLE
è ciò che utilizza l'estensione geografica di MySQL. Quando lavori in gradi, più di cinque posizioni dopo la virgola decimale superano la precisione del GPS. DECIMAL()
non è un tipo di dati ideale per le coordinate lat/lng.