Проблемът е, че начинът, по който съхранявате данни в базата данни, не е подходящ за типа задача, която изпълнявате. Използване на Point
стойности в Geometry
точките с данни е правилният начин. Всъщност кодирах нещо преди 4+ години за тази цел, но имам проблеми с намирането му. Но тази публикация изглежда го покрива добре.
РЕДАКТИРАНЕ Добре, намерих стария си код, но се отнася до стари клиентски данни, които очевидно не мога да споделя. Но ключът към скоростта с координати в базите данни е използването на POINT
данни, съхранявани в таблицата на базата данни с тип GEOMETRY
. Повече подробности тук
на официалния сайт на MySQL. Тъй като имах нужда от причина да преразгледам този тип код – и концепциите – за известно време, ето един бърз MySQL скрипт, който приготвих, за да създам примерна таблица с примерни данни, за да предам основните концепции. След като разберете какво се случва, това отваря много страхотни опции.
Намерено е също това страхотно/просто обяснение на концепцията също.
И намери друга страхотна оценка на пространствените данни в MySQL 5.6. Много страхотна информация за индексите и производителността. Конкретно по отношение на производителността на пространствения индекс на MySQL:
И от другата страна на това:
И ето моите основни скриптове за тестване на MySQL, които да помогнат за илюстрирането на концепцията:
/* 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
;