Låt oss titta på ett enkelt exempel på hur du använder STDistance
funktion i SQL Server 2008 (och senare).
Jag ska berätta för SQL Server att jag är i London, och jag vill se hur långt bort vart och ett av mina kontor är. Här är resultaten som jag vill att SQL Server ska ge mig:
Först behöver vi lite exempeldata. Vi skapar en tabell som innehåller några platser för Microsoft-kontor, och vi lagrar deras longitud- och latitudvärden i en geography
fältet.
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())
Om vi nu var i London. Så här gör du en geography
värde av Londons longitud- och latitudvärden:
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) + ')';
Och slutligen, låt oss se hur långt vart och ett av våra kontor är.
SELECT [Office_Name],
cast([Office_Location].STDistance(@g) / 1609.344 as numeric(10, 1)) as 'Distance (in miles)'
FROM [Offices]
ORDER BY 2 ASC
Och detta ger oss de resultat vi hoppades på.
Självklart kan du lägga in en TOP(1)
om du bara ville se de närmaste kontor.
Coolt, hej?
Det finns bara en hake. När du har mycket geography
poäng att jämföra med, prestanda är inte lysande, även om du lägger till ett SPATIAL INDEX i det databasfältet.
Jag testade en punkt mot en tabell med 330 000 geography
poäng. Med hjälp av koden som visas här hittade den den närmaste punkten på cirka 8 sekunder .
När jag ändrade min tabell för att lagra longitud- och latitudvärden och använde [dbo].[fnCalcDistanceMiles]
från den här StackOverflow-artikeln hittade den den närmaste punkten på ungefär 3 sekunder .
Men...
Alla "avstånd mellan två punkter"-exempel jag hittade på internet använde antingen SQL Server STDistance
funktion, eller matematiska formler som involverar de (CPU-intensiva) funktionerna cos, sin och tan.
En snabbare lösning var att resa tillbaka i tiden till gymnasiet och komma ihåg hur Pythagoras beräknade avståndet mellan två punkter.
Tänk om vi ville veta avståndet mellan London och Paris.
Och här är min SQL Server-funktion:
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
Kom nu ihåg att den här funktionen inte returnerar ett värde i miles, kilometer, etc... den jämför bara longitud- och latitudvärdena. Och Pythagoras är tänkt att användas i 2D, och inte att jämföra punkter på en rund planet!
Men i mina tester hittade den den närmaste punkten inom 1 sekund , och gav samma resultat som att använda SQL Servers STDistance
funktion.
Så använd gärna den här funktionen för att jämföra relativa avstånd , men använd inte den här funktionen om du behöver själva avståndet.
Hoppas allt detta hjälper.