puntos de consulta dentro de un radio determinado en MySQL
-
18-09-2019 - |
Pregunta
He creado la siguiente tabla de MySQL para almacenar latitud / longitud coordina junto con un nombre para cada punto:
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;
Estoy tratando de consultar:
- todos los puntos dentro de un n radio de millas de un punto dado;
- la distancia de cada punto de regresar del punto dado
Todos los ejemplos que he encontrado se refieren a la utilización de un rectángulo delimitador mínimo (MBR) en lugar de un radio. La tabla contiene aproximadamente 1 millón de puntos, por lo que esta necesidad debe ser lo más eficiente posible.
Solución 2
gracias a ambos por sus respuestas.
Al final encontré la solución en http: //www.movable -type.co.uk/scripts/latlong-db.html.
Otros consejos
Para MySQL 5.7 +
Dado que tenemos la siguiente tabla sencilla,
create table example (
id bigint not null auto_increment primary key,
lnglat point not null
);
create spatial index example_lnglat
on example (lnglat);
Con los siguientes datos sencilla,
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));
Puede conseguir los puntos dentro de un rango determinado de otro punto (nota: tenemos que buscar dentro de un polígono) con la siguiente combinación de funciones 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);
Debería ver algo como esto como resultado:
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
Para tener una referencia de la distancia, si quitamos la restricción del resultado para el punto de prueba se parece a esto:
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 : el campo se llama lnglat ya que es el orden correcto si se piensa en puntos como (x, y) y es también el orden mayoría de las funciones (como puntos) aceptar el parámetro
Nota 2 : no se puede realmente tomar ventaja de los índices espaciales si se fuera a utilizar círculos; También tenga en cuenta que el campo de punto se puede configurar para aceptar nulos índices espaciales, pero no pueden indexar que si es anulable (se requieren todos los campos en que el índice sea no nulo).
Nota 3 : ST_Buffer se considera (en la documentación) a ser malo para este caso de uso
Nota 4 : las funciones anteriores (en particular st_distance_sphere) se documentan tan rápido pero no necesariamente súper precisa; Si los datos son muy sensibles a los que añadir un poco de margen de maniobra para la búsqueda y hacer algunos ajustes para el conjunto de resultados
Radio no es eficiente indexable. Debe utilizar el rectángulo delimitador para obtener rápidamente los puntos que probablemente está buscando, y luego filtrar los puntos fuera del radio.
Lo hice durante un punto en el interior del círculo con radio
SELECT
*
FROM
`locator`
WHERE
SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`
detalles y una muestra más consulta aquí http : //dexxtr.com/post/83498801191/how-to-determine-point-inside-circle-using-mysql , espero que esta ayuda