web-dev-qa-db-fra.com

Distance minimale d'un emplacement; une table des points par rapport à un ensemble de points SQL 2012

J'essaie de trouver le moyen le plus rapide de trouver la distance minimale d'un point sur une table de points. La seule mise en garde est que le tableau des points que j'essaie de trouver la distance minimale de 150 000 points simples.

Ou mieux a expliqué la table A comporte 150 000 rangées/points, tableau B 1500 points. Je veux savoir pour chaque rangée dans le tableau A Quelle est la distance minimale de tous ceux énumérés dans le tableau B.

J'ai une fonction qui fait la distance calcaire, en tant que colonne ajoutée à la table A. Cela prend juste une très longue période. Le tableau B a un indice spatial.

C'est ce que j'ai:

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

ma fonction:

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

Désolé si je suis totalement un débutant à cela, et je sais que la solution est probablement simple, mais je ne peux tout simplement pas envelopper ma tête autour de cela. Ainsi, j'espère clarifier: j'ai besoin de passer le lat/long de chaque point dans le tableau A et de voir quelle distance la distance est comparée à toutes les rangées du tableau B, pour chaque rangée du tableau A. Je me soucie de la distance réelle, Mais pas le point réel du tableau B.

Toute aide appréciée.

5
Robert Sparrow

Vous pouvez avoir de meilleures performances si vous convertissez la fonction en une fonction de valorisation de la table.

Ici, je configurais le lit de test:

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

CREATE TABLE TableB
(
    Geolocation GEOGRAPHY NOT NULL
);
GO

Voici la fonction de valorisation de la table, qui est fondamentalement votre fonction, sauf que cela renvoie une table.

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

Insérez une simple ligne de test dans chacune des deux tables:

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)
);

La requête qui utilise le TVF en ligne pour déterminer le point le plus proche:

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