以前很傻很天真地覺得無非就是逐個計算距離,而後比較出來就好了,而後當碰到訪問用戶不少,並且數據庫中經緯度信息不少的時候,計算量的迅速增加,能讓服務器徹底傻逼掉,仍是老前輩的經驗比咱們豐富,給了我很大的啓示。git
MySQL性能調優 – 使用更爲快速的算法進行距離計算算法
最近遇到了一個問題,經過不斷的嘗試最終將某句本來佔據近1秒的查詢優化到了0.01秒,效率提升了100倍.sql
問題是這樣的,有一張存放用戶居住地點經緯度信息的MySQL數據表,表結構能夠簡化 爲:id(int),longitude(long),latitude()long. 而業務系統中有一個功能是查找離某個用戶最近的其他數個用戶,經過代碼分析,能夠肯定原先的作法基本是這樣的:數據庫
//須要查詢的用戶的座標服務器
1 |
$lat= 20 ; |
2 |
$lon= 20 ; //執行查詢,算出該用戶與全部其餘用戶的距離,取出最近的10個 |
3 |
$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語句執行時的速度..net
最終的sql語句以下code
1 |
$sql='select * from users_location where |
2 |
latitude > '.$lat.' - 1 and |
3 |
latitude < '.$lat.' + 1 and |
4 |
longitude > '.$lon.' - 1 and |
5 |
longitude < '.$lon.' + 1 |
6 |
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查詢範圍的方法也能夠適用在其餘地方.orm
原文地址: http://blog.csdn.net/hustpzb/article/details/7688993