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

标签 php mysql sorting coordinates geographic-distance

我在 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;
}
?>

最佳答案

使用 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

关于php - 从mysql数据库中选择最近地理位置的最快方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10432222/

相关文章:

php - 如何将当前文本替换/转换为所需的形式?

javascript - 如果上传的图片名称包含.php.jpg

mysql - 如何仅在变量存在时将变量插入到 SQL 查询中?

javascript - 对象数组未按正确顺序排序

python - 为什么我的随机主元快速排序比固定主元快速排序慢?

php - 如何在 Doctrine 2 中使用 WHERE IN

javascript - 将 localstorage 变量发送到 PHP

php - 将基本的 PHP/MySql 转换为 ASP 以查询 MS Sql 数据库

php - MySQL:使用时间戳,如何转换为我的用户的时区?

Unix 版本号排序