Mysql
 sql >> Database >  >> RDS >> Mysql

Query MySQL di geolocalizzazione

Il problema è che il modo in cui memorizzi i dati nel database non è adatto al tipo di attività che stai eseguendo. Usando Point valori in Geometry punti dati è la strada da percorrere. In realtà ha codificato qualcosa di più di 4 anni fa per questo scopo, ma ha problemi a trovarlo. Ma questo post sembra coprirlo bene.

MODIFICA Ok, ho trovato il mio vecchio codice, ma si riferisce ai vecchi dati del cliente che ovviamente non posso condividere. Ma la chiave per accelerare con le coordinate nei database è usare POINT dati memorizzati nella tabella del database con il tipo di GEOMETRY . Ulteriori dettagli qui sul sito ufficiale di MySQL. Dal momento che ho bisogno di una ragione per rivisitare questo tipo di codice e i concetti per un po', ecco un rapido script MySQL che ho creato per creare una tabella di esempio con dati di esempio per trasmettere i concetti di base. Una volta capito cosa sta succedendo, si aprono molte fantastiche opzioni.

Ho anche trovato questa semplice/semplice spiegazione anche del concetto.

E ho trovato un'altra grande valutazione dei dati spaziali in MySQL 5.6. Molte ottime informazioni su indici e prestazioni. In particolare per quanto riguarda le prestazioni dell'indice spaziale MySQL:

E dall'altra parte:

Ed ecco i miei script di test MySQL di base per aiutare a illustrare il concetto:

/* 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
;