web-dev-qa-db-ja.com

場所の最小距離。ポイントのセットとポイントのセットを比較したSQL 2012

ポイントのテーブルへの1つのポイントの最小距離を見つける最も速い方法を見つけようとしています。唯一の注意点は、私が最小距離を見つけようとしているポイントのテーブルが150Kのシングルポイントであることです。

または、よりよく説明すると、テーブルAは150K行/ポイント、テーブルBは1500ポイントです。表Aのすべての行について、表Bにリストされているすべての行からの最小距離を知りたい。

テーブルAに追加された列として、距離計算を実行する関数があります。非常に長い時間がかかります。テーブルBには空間インデックスがあります。

これは私が持っているものです:

select a.*, 
       dbo.fxn_distance(geography::STPointFromText('POINT(' + 
       CAST([Long] AS VARCHAR(20)) + ' ' + CAST([Lat] AS 
       VARCHAR(20)) +    ')', 4326)) as DistAway
from Table A a

私の機能:

create function fxn_distance
(@pointTableA geography
)
returns float 
as 
begin

declare @distance float

select top 1 @distance = b.GeoLocation.STDistance(@pointTableA) 
from TableB b  
where geolocation.STDistance(@pointTableA) is not null
order by geolocation.STDistance(@pointTableA)

return @distance
end

私がこれがまったくの初心者であり、解決策がおそらく単純であることを知っている場合は申し訳ありませんが、これに頭を抱えることはできません。うまくいけば明確にするために:テーブルAのすべてのポイントの緯度/経度を渡し、テーブルAのすべての行について、テーブルBのすべての行と比較した最小距離を確認する必要があります。しかし、表Bの実際のポイントではありません。

助けてくれてありがとう。

5
Robert Sparrow

関数をテーブル値関数に変換すると、パフォーマンスが向上する場合があります。

ここでは、テストベッドをセットアップします。

USE tempdb;
CREATE TABLE dbo.TableA
(
    LAT DECIMAL(10,5)
    , LON DECIMAL(10,5)
);

CREATE TABLE TableB
(
    Geolocation GEOGRAPHY NOT NULL
);
GO

これはテーブル値関数です。これは、これがテーブルを返すことを除いて、基本的に関数です。

CREATE FUNCTION dbo.fxn_distance
(
    @pointTableA GEOGRAPHY
)
returns table
as return 
(
    SELECT TOP 1 Distance = b.GeoLocation.STDistance(@pointTableA) 
    FROM TableB b  
    WHERE geolocation.STDistance(@pointTableA) IS NOT NULL
    ORDER BY geolocation.STDistance(@pointTableA)
)
GO

2つのテーブルのそれぞれに簡単なテスト行を挿入します。

INSERT INTO dbo.TableA(LAT, LON)
VALUES (49.0,170.0);

INSERT INTO dbo.TableB(Geolocation)
VALUES (geography::STGeomFromText(
    'LINESTRING(-122.360 47.656, -122.343 47.656)', 4326)
);

インラインTVFを使用して最も近いポイントを決定するクエリ:

SELECT a.*
    , d.Distance --This is the distance calculated by the TVF. 
FROM dbo.TableA a
CROSS APPLY dbo.fxn_distance(geography::STPointFromText('POINT(' + 
       CAST(A.LON AS VARCHAR(20)) + ' ' + CAST(A.LAT AS 
       VARCHAR(20)) + ')', 4326)) d ;
3
Max Vernon