指定一個經緯度,給定一個範圍值(單位:公里),查出在經緯度周圍這個範圍內的數據。
經度:113.914619
緯度:22.50128
範圍:2km
longitude爲數據表經度字段
latitude爲數據表緯度字段
SQL在mysql下測試經過,其餘數據庫可能須要修改
SQL語句以下:
select * from location where sqrt( ( ((113.914619-longitude)*PI()*12656*cos(((22.50128+latitude)/2)*PI()/180)/180) * ((113.914619-longitude)*PI()*12656*cos (((22.50128+latitude)/2)*PI()/180)/180) ) + ( ((22.50128-latitude)*PI()*12656/180) * ((22.50128-latitude)*PI()*12656/180) ) )<2mysql
最近遇到了一個問題,經過不斷的嘗試最終將某句本來佔據近1秒的查詢優化到了0.01秒,效率提升了100倍.git
問題是這樣的,有一張存放用戶居住地點經緯度信息的MySQL數據表,表結構能夠簡化 爲:id(int),longitude(long),latitude()long. 而業務系統中有一個功能是查找離某個用戶最近的其他數個用戶,經過代碼分析,能夠肯定原先的作法基本是這樣的:算法
//須要查詢的用戶的座標sql
$lat=20; $lon=20;//執行查詢,算出該用戶與全部其餘用戶的距離,取出最近的10個 $sql='select * from users_location order by ACOS(SIN(('.$lat.' * 3.1415) / 180 ) *SIN((latitude * 3.1415) / 180 ) +COS(('.$lat.' * 3.1415) / 180 ) * COS((latitude * 3.1415) / 180 ) *COS(('.$lon.' * 3.1415) / 180 - (longitude * 3.1415) / 180 ) ) * 6380 asc limit 10';
而這條sql執行的速度卻很是緩慢,用了近1秒的時間才返回結果,應該是由於order裏的子語句用了太多的數學計算公式,致使總體的運算速度降低.數據庫
而在實際的使用中,不太可能會發生須要計算該用戶與全部其餘用戶的距離,而後再排序的狀況,當用戶數量達到一個級別時,就能夠在一個較小的範圍裏進行搜索,而非在全部用戶中進行搜索.性能
因此對於這個例子,我增長了4個where條件,只對於經度和緯度大於或小於該用戶1度(111千米)範圍內的用戶進行距離計算,同時對數據表中的經度和緯度兩個列增長了索引來優化where語句執行時的速度.測試
最終的sql語句以下優化
$sql='select * from users_location where latitude > '.$lat.'-1 and latitude < '.$lat.'+1 and longitude > '.$lon.'-1 and longitude < '.$lon.'+1 order by ACOS(SIN(('.$lat.' * 3.1415) / 180 ) *SIN((latitude * 3.1415) / 180 ) +COS(('.$lat.' * 3.1415) / 180 ) * COS((latitude * 3.1415) / 180 ) *COS(('.$lon.'* 3.1415) / 180 - (longitude * 3.1415) / 180 ) ) * 6380 asc limit 10';
通過優化的sql大大提升了運行速度,在某些狀況下甚至有100倍的提高.這種從業務角度出發,縮小sql查詢範圍的方法也能夠適用在其餘地方.spa