我必须查询数千个条目的数据库,并按指定点的距离对其进行排序。
问题是每个条目都有纬度和经度,我需要检索每个条目以计算其距离。对于大型数据库,我不想检索每一行,这可能需要一些时间。
有没有办法将其构建到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
}
答案 0 :(得分:9)
选项1: 通过切换到支持GeoIP的数据库对数据库进行计算。
选项2: 使用如下存储过程对数据库进行计算:
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纬度BETWEEN $ minLat和$ maxLat以及经度BETWEEN $ minLong和$ maxLong)。然后,MySQL只需要为该行子集执行距离计算。
如果您只是使用存储过程来计算距离),那么SQL仍然必须查看数据库中的每条记录,并在它决定是否返回该行之前计算数据库中每条记录的距离或丢弃它。
因为计算执行起来相对较慢,所以如果你可以减少需要计算的行集会更好,消除明显超出所需距离的行,这样我们才会执行对于较少行数的昂贵计算。
如果你认为你正在做的事情基本上是在地图上绘制一个圆圈,以你的初始点为中心,并且距离的半径;那么公式只是简单地确定哪些行属于那个圈子......但它仍然必须检查每一行。
使用边界框就像在地图上首先绘制一个正方形,左边,右边,顶边和底边与我们的中心点保持适当的距离。然后我们的圆圈将被绘制在该框内,圆圈上的最北端,最东端,最南端和最西端的点接触到框的边界。有些行会落在该框之外,因此SQL甚至不愿意尝试计算这些行的距离。它只计算那些落在边界框内的行的距离,看它们是否也属于圆圈。
在PHP中(猜测你是从$变量名运行PHP),我们可以使用一个非常简单的计算,根据我们的距离计算出最小和最大纬度和经度,然后在WHERE子句中设置这些值您的SQL语句。这实际上就是我们的盒子,任何不属于它的东西都会被自动丢弃,而不需要实际计算它的距离。
Movable Type website对此(使用PHP代码)有一个很好的解释,对于计划在PHP中进行任何GeoPositioning工作的人来说,这应该是必不可少的阅读。
修改强> calcDistance存储过程中的值6371.01是乘数,用于以公里为单位返回返回的结果。如果您想要产生里程,海里,米,等等
,请使用适当的替代乘数答案 1 :(得分:5)
SELECT events.id FROM events
ORDER BY pow((lat - pointlat),2) + pow((lon - pointlon),2) ASC
LIMIT 0,15
您不必使用地球半径等计算绝对距离(米)。
要获得最近的点,您只需要相对距离的点数。
答案 2 :(得分:1)
答案 3 :(得分:0)
我认为stored procedures正是您所寻找的。 p>
答案 4 :(得分:0)
如果您的问题是“找到我最近的”或“商店查找器”类型的问题,那么您可以谷歌搜索这些条款。一般来说,这种类型的数据附有一些描述的邮政编码,并且可以通过与邮政编码相关联来缩小列表范围(如Mark Maker指出的那样)。
每个案例都不同,这可能不适用于你,只是把它扔到那里。