2016-08-24 110 views
1

我正在創建一個數據庫,它託管在MS SQL 2012服務器上。該數據庫的主要功能是返回距離原點一定距離內的結果。位置以緯度/經度存儲。優化SQL WHERE計算經度和緯度位置之間的距離

通過在Stack Overflow上閱讀,我發現了一個非常好的方式來查詢數據庫中我正在尋找的內容,它的功能就像一個魅力!不過,我正在考慮一種可能的方法來優化這一點。

原始SQL查詢

DECLARE @orig_lat DECIMAL(12, 9) 
DECLARE @orig_lng DECIMAL(12, 9) 

SET @orig_lat=56.xxxxxx 
SET @orig_lng=14.xxxxxx 

DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326); 

SELECT * 
FROM foobar 
WHERE @orig.STDistance(geography::Point(foobar.latitude, foobar.longitude, 4326)) < 2000 

我的猜測是,這個查詢只做返回匹配列的線性搜索foobar的表。然而,由於該表包含世界各地的位置,我想知道是否可以通過減少運行距離計算所需的行數來幫助數據庫。我的猜測是這個計算對於服務器來說很重要。

我知道請求的來源,我也知道點之間的最大距離永遠不會比說100km更大。

假設

因爲我知道,我沒有給整個世界從起源,我可以於WHERE語句提高,如下圖所示的點搜索只達100公里。通過在每個方向上將位置移動一些數字來創建經度和緯度的最小和最大邊界。

我解釋一下:

  • 產地緯度56.xxxxxx
  • 閔緯55.xxxxxx
  • 最大緯度57.xxxxxx

  • 產地經度14.xxxxxx

  • 敏經度13.xxxxxx
  • 最大經度15.xxxx xx

通過這樣做,我創建了一個圍繞原點達到約126km的區域。通過將這添加到WHERE語句中,我首先確保請求的位置在正確的範圍內。之後,我運行距離計算來獲得確切的距離。距離計算現在僅針對在最小和最大範圍內而不是整個世界內的行來運行。

優化建議

DECLARE @orig_lat DECIMAL(12, 9) 
DECLARE @orig_lng DECIMAL(12, 9) 
DECLARE @orig_latMin DECIMAL(12, 9) 
DECLARE @orig_latMax DECIMAL(12, 9) 
DECLARE @orig_lngMin DECIMAL(12, 9) 
DECLARE @orig_lngMax DECIMAL(12, 9) 

SET @orig_lat=56.xxxxxx 
SET @orig_lng=14.xxxxxx 
SET @orig_latMin=55.xxxxxx 
SET @orig_latMax=57.xxxxxx 
SET @orig_lngMin=13.xxxxxx 
SET @orig_lngMax=15.xxxxxx 

DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326); 

SELECT * 
FROM foobar 
WHERE ([latitude] > @orig_latMin 
    AND [latitude] < @orig_latMax 
    AND [longitude] > @orig_lngMin 
    AND [longitude] < @orig_lngMax) 
    AND @orig.STDistance(geography::Point(foobar.latitude, foobar.longitude, 4326)) < 2000 

我不知道數據庫的實現細節,但這確實提高了查詢或者它使情況變得更糟?我的猜測是,它取決於WHERE語句實際如何工作以及它按照什麼順序進行工作。我希望邊界檢查將在距離計算之前運行,以減少距離計算完成的時間。

編輯

剛剛實施,結果如下建議的指標建議。

沒有索引:

  • 具有優化的陳述有0,025352

  • 沒有優化的語句中的成本有0,025323

成本索引編制:

  • 具有優化的陳述有成本0,0104057

  • 沒有優化的語句有成本0,0253234

+0

檢查執行計劃 –

回答

1

一個好的經驗法則是數據庫查詢的執行時間取決於必須讀取的磁盤頁數。 CPU時間通常可以忽略。

根據這條規則,如果對磁盤頁數有所影響,您提出的優化將提高執行時間。如果緯度經度上有一個索引,將允許跳過許多表行並因此跳過許多磁盤頁面。如果是這樣的話,優化器肯定會在距離之前評估WHERE子句的那一部分。

如果沒有可以幫助這兩列的索引,我懷疑你會看到很大的差異。

+0

如果我明白你的正確。通過編輯foobar表並添加像這樣的索引。 '在foobar(緯度,經度)上創建索引index_position ;' 它應該改進查詢? – Carl

+0

如果您還沒有這些列的索引,請添加一個並嘗試。檢查執行計劃以確保它們真正被使用。 – Codo

+0

順便說一句:我不是SQLServer的空間數據支持專家。但是您應該能夠將位置保存在* geography *列中,然後在該列上創建空間索引並在其上運行優化查詢(無需計算距離的邊界矩形)。 – Codo

0

可以使用MS管理分析查詢時間Studio,在不同地方運行一個大查詢,它甚至會顯示查詢的哪一部分需要多長時間。與後邊界處顯示實際執行計劃(當你運行它)

運行一次的「邊界」,再一次:

您可以點擊Ctrl + L:顯示估計executionplan 或CTRL + M。 你將能夠看到哪個更慢,然後再次嘗試沒有邊界。

如果您沒有足夠的數據,則差異可能不可見。

相關問題