Каков самый быстрый способ выбрать ближайшее географическое место из базы данных mysql?

У меня есть таблица в базе данных mysql, содержащая геокоординаты и другую информацию о местах. Каждая строка в таблице представляет собой географическое место и имеет такие координаты, как: Latitude = 45.05235 и Longitude = 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, который дает точный ответ на ваш вопрос. Самый быстрый способ найти расстояние между двумя лат / длинными точками

Не стесняйтесь изменять по мере необходимости:

 <?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)); ?>