Przeprojektowuję bazę danych klientów, a jedną z nowych informacji, które chciałbym przechowywać wraz ze standardowymi polami adresowymi (Ulica, Miasto, itp.) Jest lokalizacja geograficzna adresu. Jedynym przypadkiem użycia, o którym myślę, jest umożliwienie użytkownikom mapowania współrzędnych na mapach Google, gdy nie można znaleźć adresu w inny sposób, co często ma miejsce, gdy obszar jest nowo zagospodarowany lub znajduje się w odległej / wiejskiej lokalizacji.
Moją pierwszą skłonnością było przechowywanie szerokości i długości geograficznej jako wartości dziesiętnych, ale potem przypomniałem sobie, że SQL Server 2008 R2 ma geographytyp danych. Nie mam absolutnie żadnego doświadczenia w używaniu geography, a z moich początkowych badań wynika, że jest to przesada w moim scenariuszu.
Na przykład, aby pracować z szerokością i długością geograficzną zapisaną jako decimal(7,4), mogę to zrobić:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
ale z geographyzrobiłbym to:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Chociaż nie jest to o wiele bardziej skomplikowane, po co dodawać złożoność, jeśli nie muszę?
Zanim porzucę pomysł używania geography, czy jest coś, co powinienem rozważyć? Czy wyszukiwanie lokalizacji przy użyciu indeksu przestrzennego byłoby szybsze niż indeksowanie pól szerokości i długości geograficznej? Czy są zalety używania geography, o których nie wiem? A może z drugiej strony, czy są zastrzeżenia, o których powinienem wiedzieć, a które zniechęciłyby mnie do używania geography?
Aktualizacja
@Erik Philips wspomniał o możliwości wyszukiwania w pobliżu geography, co jest bardzo fajne.
Z drugiej strony szybki test pokazuje, że proste selectuzyskanie szerokości i długości geograficznej jest znacznie wolniejsze podczas używania geography(szczegóły poniżej). , a komentarz dotyczący zaakceptowanej odpowiedzi na inne pytanie SO na temat geographymnie niepokoi:
@SaphuA Nie ma za co. Na marginesie należy BARDZO ostrożnie używać indeksu przestrzennego w kolumnie typu danych GEOGRAPHY dopuszczającej wartość null. Występują poważne problemy z wydajnością, więc spraw, aby kolumna GEOGRAPHY nie dopuszczała wartości null, nawet jeśli musisz przebudować swój schemat. - Tomas 18 czerwca o 11:18
Podsumowując, biorąc pod uwagę prawdopodobieństwo wykonania wyszukiwania zbliżeniowego w porównaniu z kompromisem w wydajności i złożoności, zdecydowałem się zrezygnować z użycia geographyw tym przypadku.
Szczegóły testu, który przeprowadziłem:
Utworzyłem dwie tabele, jedną używającą, geographya drugą używającą decimal(9,6)szerokości i długości geograficznej:
CREATE TABLE [dbo].[GeographyTest]
(
[RowId] [int] IDENTITY(1,1) NOT NULL,
[Location] [geography] NOT NULL,
CONSTRAINT [PK_GeographyTest] PRIMARY KEY CLUSTERED ( [RowId] ASC )
)
CREATE TABLE [dbo].[LatLongTest]
(
[RowId] [int] IDENTITY(1,1) NOT NULL,
[Latitude] [decimal](9, 6) NULL,
[Longitude] [decimal](9, 6) NULL,
CONSTRAINT [PK_LatLongTest] PRIMARY KEY CLUSTERED ([RowId] ASC)
)
i wstawił pojedynczy wiersz z tymi samymi wartościami szerokości i długości geograficznej do każdej tabeli:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Wreszcie uruchomienie poniższego kodu pokazuje, że na moim komputerze wybranie szerokości i długości geograficznej jest około 5 razy wolniejsze podczas korzystania z geography.
declare @lat float, @long float,
@d datetime2, @repCount int, @trialCount int,
@geographyDuration int, @latlongDuration int,
@trials int = 3, @reps int = 100000
create table #results
(
GeographyDuration int,
LatLongDuration int
)
set @trialCount = 0
while @trialCount < @trials
begin
set @repCount = 0
set @d = sysdatetime()
while @repCount < @reps
begin
select @lat = Location.Lat, @long = Location.Long from GeographyTest where RowId = 1
set @repCount = @repCount + 1
end
set @geographyDuration = datediff(ms, @d, sysdatetime())
set @repCount = 0
set @d = sysdatetime()
while @repCount < @reps
begin
select @lat = Latitude, @long = Longitude from LatLongTest where RowId = 1
set @repCount = @repCount + 1
end
set @latlongDuration = datediff(ms, @d, sysdatetime())
insert into #results values(@geographyDuration, @latlongDuration)
set @trialCount = @trialCount + 1
end
select *
from #results
select avg(GeographyDuration) as AvgGeographyDuration, avg(LatLongDuration) as AvgLatLongDuration
from #results
drop table #results
Wyniki:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Bardziej zaskakujące było to, że nawet jeśli nie wybrano żadnych wierszy, na przykład wybranie miejsca RowId = 2, w którym nie ma, geographybyło nadal wolniejsze:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947
