问题在于你存储在数据库中的数据方式不适合你正在执行的任务类型。使用
Geometry
数据点中的
Point
值是正确的方法。实际上,我4年前编写了一些与此相关的代码,但我现在找不到它。但这个帖子似乎涵盖得很全面。
(链接)
编辑 好的,我找到了我的旧代码,但它正在引用我显然无法分享的旧客户端数据。但在数据库表中使用存储为
GEOMETRY
类型的
POINT
数据是加快坐标处理速度的关键。在
MySQL官方网站(链接)上有更多详细信息。因为我需要一个理由重新访问这种代码和概念已经有一段时间了,所以我想出了一个快速创建一个含有样本数据的表的MySQL脚本来传达基本概念。一旦你理解了发生了什么,就会开启大量很酷的选择。
还找到了
这个关于概念的好/简单解释。
在MySQL 5.6中,另外发现了
对空间数据进行评估的另一个很好的文章。有关索引和性能的许多重要信息。特别是关于MySQL空间索引性能:
MyISAM表支持空间索引,因此上述查询将使用这些索引。
在另一方面:
InnoDB引擎不支持空间索引,因此这些查询将变得缓慢。
以下是我用来帮助说明这一概念的基本MySQL测试脚本:
CREATE DATABASE `spatial_test` CHARACTER SET utf8 COLLATE utf8_general_ci;
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 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)'));
SELECT x(`spatial_test`.`locations`.`coordinates`) AS latitude, y(`spatial_test`.`locations`.`coordinates`) AS longitude FROM `spatial_test`.`locations`;
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`
;
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
;