MySQL中地理距离搜索的方法

时间:2015-01-07 21:39:02

标签: mysql gis mysql-5.6

我正在寻找禁食方法来搜索距离另一个给定点一定距离内的点。我有一个MyISAM表,其中空间索引的点表示地理位置(纬度,经度)。

如果MySQL支持它,我认为ST_DWithin可以胜任。但它没有,所以我得到了以下表达式,它使用缓冲区生成一个圆,然后寻找属于这个圆的点:

ST_Within(geopoint, ST_Buffer(Point(@lat, @lng), @radius))

它似乎工作正常,我相信它使用索引。但这是一个足够好的解决方案吗? ST_Within和ST_Buffer在地理方面有多精确?

更新:我断定MySQL并不提供对地理坐标的支持,并且所有操作都是在欧几里德平面上完成的(即使您指定了SRID)。根据位置,最终会导致严重的不精确。因此,在使用MySQL Spatial函数之前,需要转换坐标。

1 个答案:

答案 0 :(得分:1)

我们在工作中做了类似的事情。

我们每小时获得大约100万个查询,当我们使用空间索引时,它基本上会关闭数据库,并且查询将处于挂起状态。有些查询等待约8,000秒(约2小时)。所以我们必须找到另一种方式,这是我们能想到的最好的方法,它现在不再备份数据库,并以毫秒为单位返回结果。

我们首先要做的是距离函数,如下所示:

CREATE FUNCTION `distance`(`lat1` DECIMAL(10,7), `lon1` DECIMAL(10,7), `lat2` DECIMAL(10,7), `lon2` DECIMAL(10,7)) RETURNS double
BEGIN
    DECLARE X DOUBLE;
    DECLARE PI DECIMAL(21, 20);
    SET PI = 3.14159265358979323846;
    SET X  = SIN(lat1 * PI / 180)
    * SIN(lat2 * PI / 180)
    + COS(lat1 * PI / 180)
    * COS(lat2 * PI / 180)
    * COS((lon2 * PI / 180) - (lon1 * PI / 180));
    SET X = ATAN((SQRT( 1- POWER( X, 2))) / X);
    RETURN (1.852 * 60.0 * ((X / PI) * 180)) / 1.609344;
END

在返回行上移除/ 1.609344以获得公里数

然后我们有一个程序来计算您所在位置与周围区域之间的距离。根据我们的测试,这是最快的(我们拥有的简化版本):

CREATE PROCEDURE `MyRadius`(IN `p_lat` DOUBLE, IN `p_long` DOUBLE, IN `radius` INT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN
    SELECT distance(p_lat, p_long, g.latitude, g.longitude) as distance, country, region, city
    from geocity g
    having distance <= radius
    order by distance asc limit 100;
END

您可能想要更改order子句,因为我不确定您要如何订购它。