我需要寫一個查詢,它允許我從一個提供的位置查找範圍內的所有位置(英里)。兩個座標之間的距離,我如何簡化這個和/或使用不同的技術?
表是這樣的:
id | name | lat | lng
所以我一直在做研究,發現:this my sql presentation
我已經有100行測試它在桌子上,將有大量的多! - 必須可擴展。
我嘗試一些更簡單的像這首:
//just some test data this would be required by user input
set @orig_lat=55.857807; set @orig_lng=-4.242511; set @dist=10;
SELECT *, 3956 * 2 * ASIN(
SQRT(POWER(SIN((orig.lat - abs(dest.lat)) * pi()/180/2), 2)
+ COS(orig.lat * pi()/180) * COS(abs(dest.lat) * pi()/180)
* POWER(SIN((orig.lng - dest.lng) * pi()/180/2), 2)))
AS distance
FROM locations dest, locations orig
WHERE orig.id = '1'
HAVING distance < 1
ORDER BY distance;
這返回的行圍繞50ms的這是非常好的! 但是,隨着行數的增加,這會顯着減慢。
EXPLAIN
顯示它只使用明顯的PRIMARY鍵。
然後看完文章linked above。我想是這樣的:
// defining variables - this when made into a stored procedure will call
// the values with a SELECT query.
set @mylon = -4.242511;
set @mylat = 55.857807;
set @dist = 0.5;
-- calculate lon and lat for the rectangle:
set @lon1 = @[email protected]/abs(cos(radians(@mylat))*69);
set @lon2 = @[email protected]/abs(cos(radians(@mylat))*69);
set @lat1 = @mylat-(@dist/69);
set @lat2 = @mylat+(@dist/69);
-- run the query:
SELECT *, 3956 * 2 * ASIN(
SQRT(POWER(SIN((@mylat - abs(dest.lat)) * pi()/180/2) ,2)
+ COS(@mylat * pi()/180) * COS(abs(dest.lat) * pi()/180)
* POWER(SIN((@mylon - dest.lng) * pi()/180/2), 2)))
AS distance
FROM locations dest
WHERE dest.lng BETWEEN @lon1 AND @lon2
AND dest.lat BETWEEN @lat1 AND @lat2
HAVING distance < @dist
ORDER BY distance;
此查詢的時間約爲240MS,這是不是太糟糕,但比過去的要慢。但我可以想象更多的行數會更快。然而,EXPLAIN
將可能的密鑰顯示爲lat
,lng
或PRIMARY
並且使用PRIMARY
。
我該如何做得更好?
我知道我可以將lat lng存儲爲POINT();但我也沒有找到太多的文件,這表明它是更快還是更準確?
任何其他的想法會被高興地接受!
非常感謝!
-Stefan
UPDATE:
喬納森萊弗勒指出,我做了,我沒有注意到幾個錯誤:
我只把ABS()在其中一個緯度值上。在沒有需要的情況下,我在第二個WHERE子句中使用了一個id搜索。在第一個查詢純粹是實驗性的,第二個查詢更有可能達到產量。
經過這些更改EXPLAIN
顯示現在使用的密鑰是lng
列和平均響應時間180ms這是一個改進。
Stefan,我期待着做這樣的事情..你可以發佈你的最終存儲過程嗎?我以前從來沒有寫過存儲過程,想到的第一個問題是,你的代碼看起來像它有靜態參數..我如何將myLat,myLon和距離傳遞給存儲過程,距離「miles 「 – erik 2014-06-12 19:16:40