从mysql数据库中选择最近地理位置的最快方法是什么?

时间:2012-05-03 13:17:09

标签: php mysql

我在mysql数据库中有一个表,其中包含地理坐标和有关地点的其他信息。表中的每一行代表一个地理位置,其坐标如下:纬度= 45.05235,经度= 8.02354,这是欧洲某个地方。

根据某些输入地理坐标(相同格式),我需要从该表中选择最近的地方,或者在某个半径范围内最近的地方。

我已经在使用索引了,但是我想加快这个过程,因为这些函数被多次使用。

如果我可以直接用一个查询选择最近的某个半径或某个半径内的位置,这可能会有所帮助。当然,任何其他解决方案也非常欢迎。

我做了一个函数来获取最近的位置(工作但很慢):

<?php
//Function for getting nearest destinations:
function nearest_destination($lat1,$lon1,$radius,$type,$maxdistance){
//Determine geo bounds:
$lonlow = $lon1 - rad2deg($maxdistance/6371);
$lonhigh = $lon1 + rad2deg($maxdistance/6371);
$latlow = $lat1 - rad2deg($maxdistance/6371);
$lathigh = $lat1 + rad2deg($maxdistance/6371);


//Database details and connect to database
include(realpath($_SERVER["DOCUMENT_ROOT"]).'/connect_to_db.php'); 


//Set initial counters to zero
$ii=0;
$i=0;


while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
$shortnamelist[$ii]=$row['shortname'];
$fullnamelist[$ii]=$row['fullname'];
$latitudelist[$ii]=$row['latitude'];
$longitudelist[$ii]=$row['longitude'];
$lon2=$row['longitude'];
$lat2=$row['latitude'];


//Calculate the distance:
$delta_lon = $lon2 - $lon1;
$earth_radius = "6371"; # in km
$distance  = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($delta_lon)) ;
$distance  = acos($distance);
$distance  = $earth_radius*$distance;
$distance  = round($distance, 4);
$distancelist[$ii] = $distance;
$ii=$ii+1;
}

//Select position of nearest, and select the destination
if(isset($distancelist)){
$minkey=array_keys($distancelist, min($distancelist));
$minkey=$minkey[0];

$fullname=$fullnamelist[$minkey];
$shortname=$shortnamelist[$minkey];
$latitude=$latitudelist[$minkey];
$longitude=$longitudelist[$minkey];



// remove the big arrays to conserve memory:
unset($fullnamelist);
unset($latitudelist);
unset($longitudelist);
unset($distancelist);
unset($shortnamelist);
}




if(isset($destinid)=='TRUE'){
$nearest_destination = array("shortname" => $shortname, "fullname" => $fullname, "latitude" => $latitude, "longitude" => $longitude, "distancelist" => $distancelisting);}
else $nearest_destination = 0;
mysql_close ();
return $nearest_destination;
}
?>

这是选择某个半径内最近的位置(工作但很慢)的函数:

<?php
//Function for getting nearest destinations:
function nearest_destination($lat1,$lon1,$radius,$type,$maxdistance){
//Determine geo bounds:
$lonlow = $lon1 - rad2deg($maxdistance/6371);
$lonhigh = $lon1 + rad2deg($maxdistance/6371);
$latlow = $lat1 - rad2deg($maxdistance/6371);
$lathigh = $lat1 + rad2deg($maxdistance/6371);

// Convert from string to number:
$lon1=floatval($lon1);
$lat1=floatval($lat1);


//Database details and connect to database
include(realpath($_SERVER["DOCUMENT_ROOT"]).'/connect_to_database.php'); //Get DB login details

//Select data from destinations table:
$sql="SELECT shortname, fullname, latitude, longitude FROM destinations WHERE type='$type' AND longitude > $lonlow AND longitude < $lonhigh AND latitude > $latlow AND latitude < $lathigh";
$result=mysql_query($sql);

//Set initial counter to zero
$i=0;

while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
$lon2=$row['longitude'];
$lat2=$row['latitude'];
$lon2=floatval($lon2);
$lat2=floatval($lat2);

//Calculate the distance:
$delta_lon = $lon2 - $lon1;
$earth_radius = "6371"; # in km
$distance  = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($delta_lon)) ;
$distance  = acos($distance);
$distance  = $earth_radius*$distance;
$distance  = round($distance, 4);

//If distance is smaller than the radius the destination is saved in the array:
if($distance<$radius){
$fullname[$i]=$row['fullname'];
$shortname[$i]=$row['shortname'];
$latitude[$i]=$row['latitude'];
$longitude[$i]=$row['longitude'];
$distancelisting[$i] = $distance;
$i=$i+1;
}
}


if(isset($destinid)=='TRUE'){
$nearest_destination = array("shortname" => $shortname, "fullname" => $fullname, "latitude" => $latitude, "longitude" => $longitude, "distancelist" => $distancelisting);}
else $nearest_destination = 0;
mysql_close ();
return $nearest_destination;
}
?>

2 个答案:

答案 0 :(得分:1)

使用mysql gis支持将提高您为此创建的速度。如果你经常阅读和比较距离,那么使用postgis是值得的,这是一个完整的支持地理空间数据库。它可以让你为有效的距离查询索引你的点数。 MySQL确实提供有限的支持并依赖于GEOS http://trac.osgeo.org/geos/

http://forge.mysql.com/wiki/GIS_Functions

http://postgis.refractions.net/

最相关的链接是由Anigel发表的评论发布的,它给出了问题的准确答案Fastest Way to Find Distance Between Two Lat/Long Points

答案 1 :(得分:1)

根据需要随意修改:

<?php
$center_lat = $_GET["lat"];
$center_lng = $_GET["lng"];
$radius = $_GET["radius"];
$unit = $_GET["unit"];
$unitConst = $unit == "mi" ? 3959 : 6371;
$sql = sprintf("SELECT Address, City, State, Country, PostalCode, PhoneNumber, Lat, Lng, ($unitConst * acos(cos(radians('%s')) * cos(radians(Lat)) * cos(radians(Lng) - radians('%s')) + sin(radians('%s')) * sin(radians(Lat)))) AS Distance FROM destinations WHERE (Lat != '0' AND Lng !=0) HAVING distance < '%s' ORDER BY distance", mysql_real_escape_string($center_lat), mysql_real_escape_string($center_lng), mysql_real_escape_string($center_lat), mysql_real_escape_string($radius));
?>
相关问题