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
quelle
Antworten:
Wenn Sie eine räumliche Berechnung planen, ermöglicht EF 5.0 LINQ-Ausdrücke wie:
Dann gibt es einen sehr guten Grund, Geographie zu verwenden.
Erklärung des räumlichen Rahmens innerhalb von Entity Framework .
Aktualisiert mit Erstellen von Hochleistungs-Geodatenbanken
Wie ich auf Noel Abrahams Antwort notiert habe :
Vergleichen der Speichertypen:
Ergebnis:
Der geografische Datentyp nimmt 30% mehr Platz ein.
Darüber hinaus ist der Geografiedatentyp nicht nur auf das Speichern eines Punkts beschränkt, sondern Sie können auch LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString und MultiPolygon und mehr speichern . Jeder Versuch, selbst den einfachsten Geografietyp (als Lat / Long) über einen Punkt hinaus zu speichern (z. B. LINESTRING (1 1, 2 2) -Instanz), führt zu zusätzlichen Zeilen für jeden Punkt, einer Spalte zur Sequenzierung für die Reihenfolge jedes Punkts und eine weitere Spalte zum Gruppieren von Zeilen. SQL Server verfügt auch über Methoden für die Geografie-Datentypen, einschließlich der Berechnung von Fläche, Grenze, Länge, Entfernungen und mehr .
Es erscheint unklug, Latitude und Longitude als Dezimalzahl in SQL Server zu speichern.
Update 2
Wenn Sie Berechnungen wie Entfernung, Fläche usw. durchführen möchten, ist es schwierig, diese über die Erdoberfläche richtig zu berechnen. Jeder in SQL Server gespeicherte Geografietyp wird auch mit einer räumlichen Referenz-ID gespeichert . Diese IDs können aus verschiedenen Sphären bestehen (die Erde ist 4326). Dies bedeutet, dass die Berechnungen in SQL Server tatsächlich korrekt über der Erdoberfläche berechnet werden (anstelle von Luftlinie, die durch die Erdoberfläche verlaufen könnte).
quelle
geography
und Sie haben einige gute angegeben. Letztendlich habe ich mich entschieden,decimal
in diesem Fall nur Felder zu verwenden (siehe mein langwieriges Update), aber es ist gut zu wissen, dass ich es verwenden kann,geography
wenn ich jemals etwas ausgefalleneres tun muss, als nur Koordinaten abzubilden.Eine andere zu berücksichtigende Sache ist der Speicherplatz, der von jeder Methode belegt wird. Der Geografietyp wird als gespeichert
VARBINARY(MAX)
. Versuchen Sie, dieses Skript auszuführen:Ergebnis:
Der geografische Datentyp nimmt fast doppelt so viel Platz ein.
quelle
quelle