2012-05-03 3 views
2

私は地理座標と場所に関する他の情報を含むmysqlデータベースにテーブルを持っています。テーブルの各行は地理的な場所を表し、次のような座標を持ちます:Latitude = 45.05235 and Longitude = 8.02354これはヨーロッパのどこかの場所です。mysqlデータベースから最も近い地理的な場所を選択する最速の方法は何ですか?

いくつかの入力地理的座標(同じ形式)を指定すると、そのテーブルから最も近い場所、またはある半径内の最も近い場所を選択する必要があります。

私は既にインデックスを使用していますが、これらの関数が何度も使用されているため、処理を高速化したいと考えています。

1つのクエリで特定の半径内に最も近い場所を直接選択すると役立つかもしれません。他のソリューションも非常に歓迎しています。 (ワーキングしかし遅い)

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

あなたがplanni多くの地理空間データを扱うためには、postgresql/postgisのコンボをよく見ておく価値があります。 – ChristopheD

+0

http://stackoverflow.com/questions/1006654/fastest-distance-lookup- given-latitude-longitude – 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

関連する問題