Veamos un ejemplo simple del uso de STDistance
función en SQL Server 2008 (y versiones posteriores).
Voy a decirle a SQL Server que estoy en Londres y quiero ver a qué distancia están cada una de mis oficinas. Aquí están los resultados que quiero que SQL Server me dé:
Primero, necesitaremos algunos datos de muestra. Crearemos una tabla que contenga algunas ubicaciones de las oficinas de Microsoft y almacenaremos sus valores de longitud y latitud en una geography
campo.
CREATE TABLE [Offices] (
[Office_Id] [int] IDENTITY(1, 1) NOT NULL,
[Office_Name] [nvarchar](200) NOT NULL,
[Office_Location] [geography] NOT NULL,
[Update_By] nvarchar(30) NULL,
[Update_Time] [datetime]
) ON [PRIMARY]
GO
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Zurich', 'POINT(8.590847 47.408860 )', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft San Francisco', 'POINT(-122.403697 37.792062 )', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Paris', 'POINT(2.265509 48.833946)', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Sydney', 'POINT(151.138378 -33.796572)', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Dubai', 'POINT(55.286282 25.228850)', 'mike', GetDate())
Ahora, suponiendo que estuviéramos en Londres. He aquí cómo hacer una geography
valor de los valores de longitud y latitud de Londres:
DECLARE
@latitude numeric(12, 7),
@longitude numeric(12, 7)
SET @latitude = 51.507351
SET @longitude = -0.127758
DECLARE @g geography = 'POINT(' + cast(@longitude as nvarchar) + ' ' + cast(@latitude as nvarchar) + ')';
Y por último, veamos a qué distancia está cada una de nuestras oficinas.
SELECT [Office_Name],
cast([Office_Location].STDistance(@g) / 1609.344 as numeric(10, 1)) as 'Distance (in miles)'
FROM [Offices]
ORDER BY 2 ASC
Y esto nos da los resultados que esperábamos.
Obviamente, podría introducir un TOP(1)
si solo quisieras ver el más cercano oficina.
Genial, ¿eh?
Solo hay un inconveniente. Cuando tienes mucha geography
puntos con los que comparar, el rendimiento no es brillante, incluso si agrega un ÍNDICE ESPACIAL en ese campo de la base de datos.
Probé un punto con una tabla de 330 000 geography
puntos. Usando el código que se muestra aquí, encontró el punto más cercano en aproximadamente 8 segundos .
Cuando modifiqué mi tabla para almacenar los valores de longitud y latitud, y usé [dbo].[fnCalcDistanceMiles]
función de este artículo de StackOverflow, encontró el punto más cercano en aproximadamente 3 segundos .
Sin embargo...
Todas las muestras de "distancia entre dos puntos" que encontré en Internet usaron SQL Server STDistance
o fórmulas matemáticas que involucran las funciones cos, sen y tan (con uso intensivo de CPU).
Una solución más rápida era viajar en el tiempo a la escuela secundaria y recordar cómo Pitágoras calculó la distancia entre dos puntos.
Supongamos que quisiéramos saber la distancia entre Londres y París.
Y aquí está mi función de SQL Server:
CREATE FUNCTION [dbo].[uf_CalculateDistance] (@Lat1 decimal(8,4), @Long1 decimal(8,4), @Lat2 decimal(8,4), @Long2 decimal(8,4))
RETURNS decimal (8,4) AS
BEGIN
DECLARE @d decimal(28,10)
SET @d = sqrt(square(@[email protected]) + square(@[email protected]))
RETURN @d
END
Ahora, recuerde que esta función no devuelve un valor en millas, kilómetros, etc... simplemente compara los valores de longitud y latitud. ¡Y Pitágoras está diseñado para usarse en 2D, y no para comparar puntos en un planeta redondo!
Sin embargo, en mis pruebas, encontró el punto más cercano en 1 segundo y produjo los mismos resultados que usando STDistance
de SQL Server función.
Por lo tanto, no dude en utilizar esta función para comparar distancias relativas , pero no use esta función si necesita la distancia real.
Espero que todo esto ayude.