Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête MySQL de géolocalisation

Le problème est que la façon dont vous stockez les données dans la base de données n'est pas adaptée au type de tâche que vous effectuez. Utilisation de Point valeurs dans Geometry les points de données sont la voie à suivre. En fait, j'ai codé quelque chose il y a plus de 4 ans à cette fin, mais j'ai du mal à le trouver. Mais ce message semble bien le couvrir.

MODIFIER D'accord, j'ai trouvé mon ancien code, mais il fait référence à d'anciennes données client que je ne peux évidemment pas partager. Mais la clé pour accélérer les coordonnées dans les bases de données utilise POINT données stockées dans la table de la base de données avec le type de GEOMETRY . Plus de détails ici sur le site officiel de MySQL. Comme j'avais besoin d'une raison pour revoir ce type de code - et les concepts - pendant un certain temps, voici un script MySQL rapide que j'ai préparé pour créer un exemple de table avec des exemples de données pour transmettre les concepts de base. Une fois que vous comprenez ce qui se passe, cela ouvre de nombreuses options intéressantes.

Également trouvé cette grande/simple explication du concept également.

Et trouvé une autre excellente évaluation des données spatiales dans MySQL 5.6. Beaucoup d'informations intéressantes sur les index et les performances. Spécifiquement concernant les performances de l'index spatial MySQL :

Et de l'autre côté :

Et voici mes scripts de test MySQL de base pour aider à illustrer le concept :

/* Create the database `spatial_test` */
CREATE DATABASE `spatial_test` CHARACTER SET utf8 COLLATE utf8_general_ci;

/* Create the table `locations` in `spatial_test` */
CREATE TABLE `spatial_test`.`locations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `coordinates` point NOT NULL,
  UNIQUE KEY `id` (`id`),
  SPATIAL KEY `idx_coordinates` (`coordinates`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

/* Insert some test data into it. */
INSERT INTO `spatial_test`.`locations` (`id`, `coordinates`) VALUES (NULL, GeomFromText('POINT(27.174961 78.041822)'));
INSERT INTO `spatial_test`.`locations` (`id`, `coordinates`) VALUES (NULL, GeomFromText('POINT(27.985818 86.923596)'));
INSERT INTO `spatial_test`.`locations` (`id`, `coordinates`) VALUES (NULL, GeomFromText('POINT(44.427963 -110.588455)'));
INSERT INTO `spatial_test`.`locations` (`id`, `coordinates`) VALUES (NULL, GeomFromText('POINT(19.896766 -155.582782)'));
INSERT INTO `spatial_test`.`locations` (`id`, `coordinates`) VALUES (NULL, GeomFromText('POINT(40.748328 -73.985560)'));
INSERT INTO `spatial_test`.`locations` (`id`, `coordinates`) VALUES (NULL, GeomFromText('POINT(40.782710 -73.965310)'));

/* A sample SELECT query that extracts the 'latitude' & 'longitude' */
SELECT x(`spatial_test`.`locations`.`coordinates`) AS latitude, y(`spatial_test`.`locations`.`coordinates`) AS longitude FROM `spatial_test`.`locations`;

/* Another sample SELECT query calculates distance of all items in database based on GLength using another set of coordinates. */
SELECT GLength(LineStringFromWKB(LineString(GeomFromText(astext(PointFromWKB(`spatial_test`.`locations`.`coordinates`))), GeomFromText(astext(PointFromWKB(POINT(40.782710,-73.965310))))))) AS distance
FROM `spatial_test`.`locations`
;

/* Yet another sample SELECT query that selects items by using the Earth’s radius. The 'HAVING distance < 100' equates to a distance of less than 100 miles or kilometers based on what you set the query for. */
/* Earth’s diameter in kilometers: 6371 */
/* Earth’s diameter in miles: 3959 */
SELECT id, (3959 * acos(cos(radians(40.782710)) * cos(radians(x(`spatial_test`.`locations`.`coordinates`))) * cos(radians(y(`spatial_test`.`locations`.`coordinates`)) - radians(-73.965310)) + sin(radians(40.782710)) * sin(radians(x(`spatial_test`.`locations`.`coordinates`))))) AS distance 
FROM `spatial_test`.`locations`
HAVING distance < 100
ORDER BY id
;