2012-05-03 57 views
2

我有一個包含地理座標和其他地方信息的MySQL數據庫中的表。表格中的每一行都代表一個地理位置,並具有座標,如:緯度= 45.05235和經度= 8.02354,這是歐洲的某個地方。從mysql數據庫中選擇最近的地理位置的最快方法是什麼?

在某些輸入的地理座標(相同的格式)上,我需要從該表中選擇最近的地方或某個半徑內的最近地點。

我已經在使用索引,但是我想加快這個過程,因爲這些函數被多次使用。

如果我可以直接用一個查詢選擇最近的地點或某個半徑範圍內的地點,這可能會有所幫助。當然任何其他解決方案也非常好。

我提出,得到最近的地方的功能(這是工作,但慢):

<?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; 
} 
?> 
+0

如果您計劃ng來處理大量的地理空間數據,這可能是值得有一個很好的看看postgresql/postgis組合... – ChristopheD

+0

你看過http://stackoverflow.com/questions/1006654/fastest-distance-lookup-給定緯度經度 – Anigel

回答

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

+0

你認爲這是使用mysql時最快的方法嗎? – BastiaanWW

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

考慮切換到PHP的PDO或一些等價物,因爲mysql_ *處於軟棄用的開始階段。 – maiorano84

+0

你認爲這是使用mysql時最快的方法嗎? – BastiaanWW

+0

我確實。您不需要依靠PHP來計算您需要的所有內容,而是將所有內容一次全部通過一次查詢發送到數據庫,從而得出您需要的結果。 – maiorano84

相關問題