1. 程式人生 > >sql語句查詢經緯度範圍

sql語句查詢經緯度範圍

MySQL效能調優 – 使用更為快速的演算法進行距離

最近遇到了一個問題,通過不斷的嘗試最終將某句原本佔據近1秒的查詢優化到了0.01秒,效率提高了100倍.

問題是這樣的,有一張存放使用者居住地點經緯度資訊的MySQL資料表,表結構可以簡化 為:id(int),longitude(long),latitude()long. 而業務系統中有一個功能是查詢離某個使用者最近的其餘數個使用者,通過程式碼分析,可以確定原先的做法基本是這樣的:

//需要查詢的使用者的座標

$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查詢範圍的方法也可以適用在其他地方.