我目前在mysql数据库中有不到一百万个位置,都有经度和纬度信息。
我试图通过查询找到一个点和许多其他点之间的距离。它没有我想要的那么快,尤其是每秒100+次。
有没有比mysql更快的查询或更快的系统?我使用这个查询:
SELECT
name,
( 3959 * acos( cos( radians(42.290763) ) * cos( radians( locations.lat ) )
* cos( radians(locations.lng) - radians(-71.35368)) + sin(radians(42.290763))
* sin( radians(locations.lat)))) AS distance
FROM locations
WHERE active = 1
HAVING distance < 10
ORDER BY distance;
注:提供的距离单位为英里。如果需要公里,请使用6371而不是3959。
使用mysql
SET @orig_lon = 1.027125;
SET @dest_lon = 1.027125;
SET @orig_lat = 2.398441;
SET @dest_lat = 2.398441;
SET @kmormiles = 6371;-- for distance in miles set to : 3956
SELECT @kmormiles * ACOS(LEAST(COS(RADIANS(@orig_lat)) *
COS(RADIANS(@dest_lat)) * COS(RADIANS(@orig_lon - @dest_lon)) +
SIN(RADIANS(@orig_lat)) * SIN(RADIANS(@dest_lat)),1.0)) as distance;
参见:https://andrew.hedges.name/experiments/haversine/
参见:https://stackoverflow.com/a/24372831/5155484
参见:http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
注意:LEAST用于避免null值,如https://stackoverflow.com/a/24372831/5155484上建议的注释
我需要解决类似的问题(从单点的距离过滤行),并通过结合原始问题的答案和评论,我想出了解决方案,这对我来说完美的MySQL 5.6和5.7。
SELECT
*,
(6371 * ACOS(COS(RADIANS(56.946285)) * COS(RADIANS(Y(coordinates)))
* COS(RADIANS(X(coordinates)) - RADIANS(24.105078)) + SIN(RADIANS(56.946285))
* SIN(RADIANS(Y(coordinates))))) AS distance
FROM places
WHERE MBRContains
(
LineString
(
Point (
24.105078 + 15 / (111.320 * COS(RADIANS(56.946285))),
56.946285 + 15 / 111.133
),
Point (
24.105078 - 15 / (111.320 * COS(RADIANS(56.946285))),
56.946285 - 15 / 111.133
)
),
coordinates
)
HAVING distance < 15
ORDER By distance
坐标是POINT类型的字段,具有空间索引
6371是用千米来计算距离的
56.946285为中心点纬度
24.105078为中心点经度
15是最大距离,单位为千米
在我的测试中,MySQL使用SPATIAL index on coordinates字段来快速选择矩形内的所有行,然后为所有过滤过的地方计算实际距离,以排除矩形角落中的地方,只留下圆圈内的地方。
这是我的结果的可视化:
灰色星形表示地图上的所有点,黄色星形表示MySQL查询返回的点。矩形(但圆圈外)角内的灰色星星由MBRContains()选择,然后由HAVING子句取消选择。
下面的MySQL函数发布在这篇博文上。我还没有对它进行太多测试,但从我从帖子中收集到的内容来看,如果你的纬度和经度字段被索引了,这可能对你很有用:
DELIMITER $$
DROP FUNCTION IF EXISTS `get_distance_in_miles_between_geo_locations` $$
CREATE FUNCTION get_distance_in_miles_between_geo_locations(
geo1_latitude decimal(10,6), geo1_longitude decimal(10,6),
geo2_latitude decimal(10,6), geo2_longitude decimal(10,6))
returns decimal(10,3) DETERMINISTIC
BEGIN
return ((ACOS(SIN(geo1_latitude * PI() / 180) * SIN(geo2_latitude * PI() / 180)
+ COS(geo1_latitude * PI() / 180) * COS(geo2_latitude * PI() / 180)
* COS((geo1_longitude - geo2_longitude) * PI() / 180)) * 180 / PI())
* 60 * 1.1515);
END $$
DELIMITER ;
示例用法:
假设有一个名为places的表,其中包含纬度和经度字段:
SELECT get_distance_in_miles_between_geo_locations(-34.017330, 22.809500,
AS distance_from_input FROM places;