Ich gestalte eine Kundendatenbank neu und eine der neuen Informationen, die ich zusammen mit den Standardadressfeldern (Straße, Stadt usw.) speichern möchte, ist der geografische Standort der Adresse. Der einzige Anwendungsfall, an den ich denke, besteht darin, Nutzern das Zuordnen der Koordinaten auf Google Maps zu ermöglichen, wenn die Adresse nicht anderweitig gefunden werden kann. Dies tritt häufig auf, wenn das Gebiet neu entwickelt wurde oder sich an einem abgelegenen / ländlichen Ort befindet.
Meine erste Neigung bestand darin, Breiten- und Längengrade als Dezimalwerte zu speichern, aber dann fiel mir ein, dass SQL Server 2008 R2 einen geography
Datentyp hat. Ich habe absolut keine Erfahrung damit geography
und nach meinen ersten Recherchen scheint es für mein Szenario übertrieben zu sein.
Um beispielsweise mit Längen- und Breitengraden zu arbeiten, die als gespeichert sind decimal(7,4)
, kann ich Folgendes tun:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
aber mit geography
würde ich das machen:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Obwohl es nicht , dass viel komplizierter, warum Komplexität , wenn ich nicht haben?
Gibt geography
es etwas, das ich berücksichtigen sollte, bevor ich die Idee der Verwendung aufgeben kann? Wäre es schneller, mithilfe eines räumlichen Index nach einem Ort zu suchen, als die Breiten- und Längengrade zu indizieren? Gibt es Vorteile bei der Verwendung geography
, die mir nicht bekannt sind? Oder gibt es auf der anderen Seite Vorbehalte, die ich kennen sollte und die mich davon abhalten würden, sie zu verwenden geography
?
Aktualisieren
@Erik Philips hat die Möglichkeit zur Suche in der Nähe angesprochen geography
, was sehr cool ist.
Auf der anderen Seite zeigt ein schneller Test, dass ein einfach select
zu ermittelnder Längen- und Breitengrad bei der Verwendung erheblich langsamer ist geography
(Details unten). und ein Kommentar zur akzeptierten Antwort auf eine andere SO-Frage geography
hat mich misstrauisch gemacht:
@SaphuA Gern geschehen. Als Nebenbemerkung sollten Sie SEHR vorsichtig sein, wenn Sie einen räumlichen Index für eine nullfähige GEOGRAPHY-Datentypspalte verwenden. Es gibt einige schwerwiegende Leistungsprobleme. Machen Sie diese GEOGRAPHY-Spalte daher nicht nullwertfähig, selbst wenn Sie Ihr Schema neu gestalten müssen. - Tomas 18. Juni um 11:18 Uhr
Alles in allem habe ich mich entschlossen, geography
in diesem Fall auf die Verwendung von Proximity-Suchen im Vergleich zum Kompromiss zwischen Leistung und Komplexität zu verzichten .
Details des Tests, den ich durchgeführt habe:
Ich habe zwei Tabellen erstellt, eine mit geography
und eine mit decimal(9,6)
Längen- und Breitengrad:
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)
)
und in jede Tabelle eine einzelne Zeile mit denselben Breiten- und Längenwerten eingefügt:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Das Ausführen des folgenden Codes zeigt schließlich, dass auf meinem Computer die Auswahl des Breiten- und Längengrads bei Verwendung ungefähr fünfmal langsamer ist 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
Ergebnisse:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Überraschender ist, dass selbst wenn keine Zeilen ausgewählt sind, beispielsweise die Auswahl von Orten RowId = 2
, die nicht vorhanden sind, geography
noch langsamer war:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947