我正在創建一個數據庫,它託管在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
檢查執行計劃 –