2016-08-02 59 views
0

是否有改善以下查詢任何可能的方式:SQL Server的地理

DECLARE @radiusInMeters FLOAT = 400; 
DECLARE @dgeog geography = geography::Point(given_latitude, given_longitude, 4326).STBuffer(@radiusInMeters); 

select [fdx].latitude, [fdx].longitude 
from [dbo].[fdx] 
where @dgeog.STIntersects(geography::STGeomFromText('POINT(' + convert(varchar(20), [fdx].longitude) + ' ' + convert(varchar(20), [fdx].latitude) + ')', 4326) 
         ) = 1 
+3

以什麼方式改進? –

+1

您的qurey不使用任何空間索引,並且您的表格沒有幾何列。所以查詢運行時間太長了。 –

+0

我的問題有點令人誤解。對不起。我的表具有地理欄和空間索引。然而,空間索引並未出現在執行計劃中。也許它必須以創建地理區域的方式 – ancdev

回答

3

kcung和哈桑BINBOGA是正確的,你需要一個空間索引。

查看您的查詢: @ dgeog.STIntersects(xxxx)= 1 這需要[xxxx]爲地理數據類型。爲了使[xxxx]成爲地理數據類型,必須將STGeomFromText函數應用於該行。由於這是WHERE子句的唯一部分,因此必須將該函數應用於全部行。

如果表fdx特別大,這意味着CLR函數將不得不重複應用。這不是(以SQL-Server術語來說)一個快速過程。

試試這個,如果可以的話:

ALTER dbo.fdx ADD Point AS (GEOGRAPHY::Point(Latitude, Longitude, 4326)) PERSISTED 
GO 
CREATE SPATIAL INDEX SIndex_FDX ON dbo.fdx (Point) 
USING GEOGRAPHY_GRID 
WITH (
    GRIDS = (LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
    CELLS_PER_OBJECT = 1 
) 
GO 
DECLARE @Latitude DECIMAL(15,10) = 0 
DECLARE @Longitude DECIMAL(15,10) = 0 
DECLARE @Radius FLOAT = 400 
DECLARE @g GEOGRAPHY = GEOGRAPHY::Point(@Latitude, @Longitude, 4326).STBuffer(@Radius) 
SELECT * FROM dbo.fdx WHERE Point.STIntersects(@g) = 1 

的注意事項:請在您的拉/長對轉換爲小數使用它們來計算地理列前。當您使用浮點數作爲將您的座標修剪至小數點後4位的輸入時,存在從float到decimal的隱式轉換。如果你明確地先轉換,那不會是一個問題。

另外,如果您在dbo.fdx中有任何空的lat/long值,則需要在WHERE子句中過濾它們,因爲空值會導致您的空間索引無法正常工作。

+0

正如我在我對Hasan BINBOGA的回覆中提到的那樣,空間索引出現在執行計劃中。但是,我使用您的語句重新創建了列,現在執行計劃是不同的。 – ancdev

+1

@ancdev空間索引與空間列相關聯。在您的查詢中,您從不參考空間列,而是使用GEOGRAPHY :: STPointFromText()計算空間值,並且出於顯而易見的原因計算出的值不能被空間索引引用。 – hcaelxxam