2016-07-24 45 views
1

目前我有幾個100k +行的表。我正在試圖查找如下的數據。什麼是在半徑內查找大表的最快方法MySQL(緯度經度)

SELECT 
*, SQRT(POW(69.1 * (latitude - '49.1044302'), 2) + POW(69.1 * ('-122.801094' - longitude) * COS(latitude/57.3), 2)) AS distance 
FROM stops 
HAVING distance < 5 
ORDER BY distance limit 100 

但是目前這種方法在高負載下會變慢。有些查詢需要20多秒才能完成。

如果有誰知道什麼更好的方法來優化這將是巨大的。

+0

這很複雜:[_scalable lat/lng searches_](https://mariadb.com/kb/en/latitudelongitude-indexing/) –

+0

您是否按照建議檢查了mysql地理空間類型? – e4c5

回答

2

那麼首先,如果你有大量的地理空間數據,你應該使用MySQL的地理空間擴展,而不是像這樣的計算。然後你可以使用create spatial indexes來加速很多查詢,而且你不必編寫像上面那樣的長時間查詢。

使用與ST_Distance的比較或創建一個帶有感興趣的半徑和ST_within的幾何圖形可能會給您帶來好的結果,並且可能會比當前快得多。然而,最好和最快的方式來實現這一點,ST_Dwithin尚未在mysql中實現。

+1

使用空間函數來獲得一組粗略匹配*並且仍然使用WHERE子句中的當前謂詞以及空間分析函數來添加空間索引也是可行的。優化器會自動知道(這很聰明)使用空間索引在大致正確的區域中找到候選匹配,然後進一步縮小它們,「使用where」按照非空間謂詞過濾匹配行,給出在保持現有邏輯的精度的同時性能更好。空間絕對是前進的道路。 –

+0

原始查詢的公式也可以在存儲函數內部重寫,該函數計算並返回表示距目標位置距離x的邊界框的多邊形,因爲iirc'ST_Distance'不是半橫軸,它是平面的。 –

1

空間索引絕對取決於MySQL版本。我們的網站也搜索緯度/經度,但我們使用的是舊版本的MySQL(5.1-something)(沒有空間索引)。您的查詢與我們的查詢類似,但我們的查詢基於弧度。根據你的確切需求,你可以優化它(從你有什麼)相當多。

  1. 絕對從數據庫查詢降SQRT(),它具有以計算每一行 - 僅在端部顯示所述實際距離給用戶時計算它 - 也是方形的「具有距離< 5「到」< 25「。 Sqrt非常昂貴並且很容易移動到不需要計算的地方。
  2. 所享有的經/緯度'49 0.1044302' 所以它是嚴格意義上的int和做經/緯度型查詢外檢查。這不會加速它,但會防止由於lat/lon變量中僞隨機空白造成的不正確轉換。
  3. 將5轉換爲每個方向上實際緯度/經度的差值+/5,以產生一個限制範圍(原來是一個方塊)。將它添加到查詢的「where」部分 - 這個限制會讓你得到一個大大減少的,幾乎精確的結果行集合 - 基本上,經緯度的x和y +/-範圍是結果的上限 - 計算出的對角線僅略微影響結果及其距離。
  4. 移動儘可能多的數學之外的選擇,並在那裏 - 它必須要掃描整個表,並創建一個臨時的,在計算每一行,給你的結果。查詢中的很多數學可以轉換爲常量。
  5. 加快行還原(選擇框)更加通過降低對緯度/經度(複製)分辨率到另一個場(也許乘以10或100 &轉換爲INT)和添加在該索引字段,並在那裏使用該字段的+/-邊界,至少可以使用一個鍵--MySQL可以減少和更快的結果。

至少這是我們如何做到這一點。

+0

'49.1044302'不是「一個整數」。 「一個數字」會做。而且,比較數字列時引號並不重要。 –

+0

邊界框(#3)是這個答案中最有生產力的部分 - 假設你有'INDEX(緯度)'或'INDEX(經度)'。 –

+0

瑞克錯誤。雖然「float」不是「int」,但他應該乘以經緯度並降低精度以從數值優選的整數索引中受益。此外,報價也很重要,但不是因爲你的意思。如果一個空格以某種方式將它變成lat或long變量字符串,那麼「$ var」不會被mysql優化器轉換爲數字。通過留下引號,任何錯誤的空間(可能來自用戶輸入)都會在sql本身結束空間,並且變得無害。不要太快才能按下「白癡按鈕」。 – Beracah

相關問題