2010-03-09 8 views
8

ho creato la seguente tabella di MySQL per memorizzare latitudine/longitudine coordina insieme ad un nome per ogni punto:punti query all'interno di un determinato raggio in MySQL

CREATE TABLE `points` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(128) NOT NULL, 
    `location` point NOT NULL, 
    PRIMARY KEY (`id`), 
    SPATIAL KEY `location` (`location`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; 

sto cercando di interrogare:

  • tutti i punti all'interno di un raggio n. di un determinato punto;
  • la distanza di ciascun punto restituito da un dato punto

Tutti gli esempi che ho trovato si riferisce all'utilizzo di un rettangolo minimo (MBR) anziché un raggio. La tabella contiene circa 1 milione di punti, quindi questa necessità deve essere il più efficiente possibile.

risposta

3

Grazie a entrambi per le vostre risposte.

Alla fine ho trovato la soluzione a http://www.movable-type.co.uk/scripts/latlong-db.html.

+0

Cosa hai fatto per risolvere questo problema? Sto lottando con la decisione di utilizzare le funzioni spaziali di MySQL 5.7 o di usare la formula di Haversine. – Jethro

2

Il raggio non è indicizzabile in modo efficiente. Dovresti usare il rettangolo di delimitazione per ottenere rapidamente i punti che stai probabilmente cercando, e quindi filtrare i punti al di fuori del raggio.

+0

Grazie per la tua risposta. La limitazione dell'indice del raggio è solo un problema in MySQL? Mi chiedo se PostgreSQL potrebbe essere più praticabile? Come eliminerei i punti dal rettangolo di delimitazione che non giace nel raggio? – gjb

+2

No, questo è un problema generale. PostgreSQL ti rende più facile, perché puoi chiedere esplicitamente se il punto è contenuto in un cerchio e questo dovrebbe usare l'indice nel modo migliore, ma credo che utilizzerebbe anche solo una ricerca rettangolare. Non riesco a vedere nessuna funzione MySQL per farlo, ma puoi calcolare semplicemente la distanza tra il centro e il punto. –

3

Per MySQL 5.7+

Dato che avere la seguente tabella semplice,

create table example (
    id bigint not null auto_increment primary key, 
    lnglat point not null 
); 

create spatial index example_lnglat 
    on example (lnglat); 

con i seguenti dati semplici,

insert into example (lnglat) 
values 
(point(-2.990435, 53.409246)), 
(point(-2.990037, 53.409471)), 
(point(-2.989736, 53.409676)), 
(point(-2.989554, 53.409797)), 
(point(-2.989350, 53.409906)), 
(point(-2.989178, 53.410085)), 
(point(-2.988739, 53.410309)), 
(point(-2.985874, 53.412656)), 
(point(-2.758019, 53.635928)); 

Si otterrebbe i punti entro un determinato intervallo di un altro punto (nota: dobbiamo cercare all'interno di un poligono) con la seguente combinazione di funzioni st:

set @px = -2.990497; 
set @py = 53.410943; 
set @range = 150; -- meters 
set @rangeKm = @range/1000; 

set @search_area = st_makeEnvelope (
    point((@px + @rangeKm/111), (@py + @rangeKm/111)), 
    point((@px - @rangeKm/111), (@py - @rangeKm/111)) 
); 

select id, 
     st_x(lnglat) lng, 
     st_y(lnglat) lat, 
     st_distance_sphere(point(@px, @py), lnglat) as distance 
    from example 
where st_contains(@search_area, lnglat); 

si dovrebbe vedere qualcosa di simile a questo come un risultato:

3 -2.989736 53.409676 149.64084252776277 
4 -2.989554 53.409797 141.93232714661812 
5 -2.98935 53.409906 138.11516275402533 
6 -2.989178 53.410085 129.40289289527473 

per riferimento alla distanza, se togliamo il vincolo il risultato del test punto assomiglia a questo:

1 -2.990435 53.409246 188.7421181457556 
2 -2.990037 53.409471 166.49406509160158 
3 -2.989736 53.409676 149.64084252776277 
4 -2.989554 53.409797 141.93232714661812 
5 -2.98935 53.409906 138.11516275402533 
6 -2.989178 53.410085 129.40289289527473 
7 -2.988739 53.410309 136.1875540498202 
8 -2.985874 53.412656 360.78532732013963 
9 -2.758019 53.635928 29360.27797292756 

Nota 1: il campo si chiama lnglat dato che è l'ordine corretto se si pensa di punti come (x, y) ed è anche l'ordine maggior parte delle funzioni (come punto) accettare il parametro

Nota 2: non è possibile utilizzare gli indici spaziali se si utilizzano i cerchi; si noti inoltre che il campo punto può essere impostato in modo da accettare null, ma gli indici spaziali non possono indicizzarlo se è nullable (tutti i campi dell'indice devono essere non null).

Nota 3: ST_Buffer è considerato (dalla documentazione) per essere un male per questo caso d'uso

Nota 4: le funzioni di cui sopra (in particolare st_distance_sphere) sono documentati più veloce, ma non necessariamente super-accurate ; se i tuoi dati sono molto sensibili, aggiungi un po 'di spazio per la ricerca e sintonizzati sul risultato

+0

Forse sto fraintendendo, ma usando 'st_contains' questo non sta ancora facendo calcoli all'interno di un piano cartesiano? Terra non sferica come si desidera? – Twig

+0

Ciao, sto usando il tuo codice qui sopra, ho una domanda, cosa significa @rangeKm/111? A cosa serve il 111? –

Problemi correlati