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 geography
typ 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 geography
zrobił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 select
uzyskanie 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 geography
mnie 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 geography
w tym przypadku.
Szczegóły testu, który przeprowadziłem:
Utworzyłem dwie tabele, jedną używającą, geography
a 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, geography
było nadal wolniejsze:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947