Нека разгледаме прост пример за използване на STDistance
функция в SQL Server 2008 (и по-нова версия).
Ще кажа на SQL Server, че съм в Лондон и искам да видя колко далеч е всеки един от моите офиси. Ето резултатите, които искам да ми даде SQL Server:
Първо, ще ни трябват някои примерни данни. Ще създадем таблица, съдържаща няколко местоположения на офиси на Microsoft и ще съхраняваме техните стойности за дължина и ширина в geography
поле.
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())
Сега, да предположим, че сме в Лондон. Ето как да направите geography
стойност извън стойностите на географската дължина и ширина на Лондон:
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) + ')';
И накрая, нека видим колко далеч е всеки един от нашите офиси.
SELECT [Office_Name],
cast([Office_Location].STDistance(@g) / 1609.344 as numeric(10, 1)) as 'Distance (in miles)'
FROM [Offices]
ORDER BY 2 ASC
И това ни дава резултатите, на които се надявахме.
Очевидно можете да въведете TOP(1)
ако просто искате да видите най-близкия офис.
Страхотно, хей?
Има само една пречка. Когато имате много geography
точки за сравнение, производителността не е брилянтна, дори ако добавите ПРОСТРАНСТВЕН ИНДЕКС към това поле на базата данни.
Тествах точка срещу таблица от 330 000 geography
точки. Използвайки показания тук код, той намери най-близката точка за около 8 секунди .
Когато промених таблицата си, за да съхранявам стойностите за географска дължина и ширина, и използвах [dbo].[fnCalcDistanceMiles]
функция от тази статия на StackOverflow, тя намери най-близката точка за около 3 секунди .
Въпреки това...
Всички проби за "разстояние между две точки", които намерих в интернет, използваха SQL Server STDistance
функция или математически формули, включващи (интензивните на процесора) функции cos, sin и tan.
По-бързото решение беше да пътувате назад във времето до гимназията и да си спомните как Питагор е изчислил разстоянието между две точки.
Да предположим, че искаме да знаем разстоянието между Лондон и Париж.
И ето моята функция на 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
Сега, запомнете, че тази функция не връща стойност в мили, километри и т.н.... а просто сравнява стойностите за дължина и ширина. И Pythagoras е предназначен да се използва в 2D, а не да се сравняват точки на кръгла планета!
При моите тестове обаче откри най-близката точка в рамките на 1 секунда и даде същите резултати като използването на STDistance
на SQL Server функция.
Така че, не се колебайте да използвате тази функция за сравняване на относителни разстояния , но не използвайте тази функция, ако имате нужда от самото действително разстояние.
Надявам се всичко това да помогне.