2010-10-21 138 views
1

我必须查询数千个条目的数据库,并按照距指定点的距离排序。在mysql查询中的距离计算

问题是,每个条目都有一个经度和纬度,我需要检索每个条目来计算它的距离。对于大型数据库,我不想检索每一行,这可能需要一些时间。

有没有什么办法可以将它建立到mysql查询中,这样我只需要检索最近的15个条目。

E.g.

`SELECT events.id, caclDistance($latlng, events.location) AS distance FROM events ORDER BY distance LIMIT 0,15` 

    function caclDistance($old, $new){ 
     //Calculates the distance between $old and $new 
    } 

回答

9

选项1: 通过切换到支持GeoIP的数据库来对数据库进行计算。

选项2: 请在这样的databaseusing存储过程中的计算:

CREATE FUNCTION calcDistance (latA double, lonA double, latB double, LonB double) 
    RETURNS double DETERMINISTIC 
BEGIN 
    SET @RlatA = radians(latA); 
    SET @RlonA = radians(lonA); 
    SET @RlatB = radians(latB); 
    SET @RlonB = radians(LonB); 
    SET @deltaLat = @RlatA - @RlatB; 
    SET @deltaLon = @RlonA - @RlonB; 
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) + 
    COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2); 
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01; 
END// 

如果您对您的数据库中的纬度和经度索引,可以减少需要计算的次数通过在PHP中创建初始边界框($ minLat,$ maxLat,$ minLong和$ maxLong)并将行限制为您的条目子集(WHERE latitude BETWEEN $ minLat AND $ maxLat和经度BETWEEN $ minLong AND $ maxLong)。那么MySQL只需要执行该行子集的距离计算。

如果您只是使用存储过程来计算距离),那么SQL仍然需要查看数据库中的每条记录,并计算数据库中每条记录的距离,然后才能决定是否返回排或放弃它。

因为计算执行起来相对较慢,所以如果您可以减少需要计算的行集合,消除显然会超出所需距离的行,那么我们只会执行对于较少数量的行来说,这是昂贵的计算。

如果你认为你正在做的事情基本上是在地图上画一个圆,以你的初始点为中心,并且有一个距离半径;那么该公式只需确定哪些行位于该圆圈内......但它仍然需要检查每一行。

使用边界框就像在地图上首先绘制一个正方形,左边,右边,顶部和底部边距离我们中心点的适当距离。然后我们的圈子将被绘制在该框内,圆圈上最北端,最东端,最南端和最西端的点与框的边界接触。有些行将落在该框之外,所以SQL甚至不打算计算这些行的距离。它仅计算落在边界框内的那些行的距离,以查看它们是否落入圆内。

在你的PHP中(猜测你正在从$变量名运行PHP),我们可以使用一个非常简单的计算,根据我们的距离计算最小和最大经度和纬度,然后将这些值设置为WHERE你的SQL语句的子句。这实际上就是我们的盒子,任何超出此范围的东西都会自动丢弃,而无需实际计算其距离。

对于任何计划在PHP中执行任何GeoPositioning工作的人来说,这应该是必不可少的解释(使用PHP代码)。

EDIT calcDistance存储过程中的值6371.01是以乘数表示的返回结果,以千米为单位。如果你想造成,海里,米,使用适当的替代乘数无论

+0

随着_”支持GeoIP'_数据库,你实际上意味着_'with空间或地理编码indexes'_(例如PostGIS的等)?我没有看到'IP'的点'有关问题GeoIP';) – Wrikken 2010-10-21 11:10:20

+0

@Wrikken PostGIS的是在我的脑海里的数据库,当我输入的IP被输入了“支持的GeoIP数据库” ... 没有想到,因为我一直在玩IP阅读经纬度,并且最近用它作为距离计算的基准位置。 – 2010-10-21 11:16:10

0

如果你的问题是“找到离我最近的”或“商店查找器”类型的问题,那么你可以谷歌这些术语。一般来说,该类型的数据伴随着一些描述的邮政编码,并且可以通过与邮政编码相关联来缩小列表(如Mark Maker指出的)。

每个情况是不同的,这可能并不适用于你,只是把它扔在那里。

4
SELECT events.id FROM events 
ORDER BY pow((lat - pointlat),2) + pow((lon - pointlon),2) ASC 
LIMIT 0,15 

您不必计算绝对距离,以米为单位,使用地球半径等等。

要获得最近的点,您只需要按相对距离排序的点。