Je suis en train de refondre une base de données clients et l'une des nouvelles informations que je souhaite stocker avec les champs d'adresse standard (rue, ville, etc.) est l'emplacement géographique de l'adresse. Le seul cas d'utilisation que j'ai à l'esprit est de permettre aux utilisateurs de cartographier les coordonnées sur Google Maps lorsque l'adresse ne peut pas être trouvée autrement, ce qui se produit souvent lorsque la zone est nouvellement développée ou se trouve dans un endroit éloigné / rural.
Ma première inclination était de stocker la latitude et la longitude sous forme de valeurs décimales, mais je me suis ensuite souvenu que SQL Server 2008 R2 avait un geography
type de données. Je n'ai absolument aucune expérience d'utilisation geography
, et d'après mes recherches initiales, cela semble excessif pour mon scénario.
Par exemple, pour travailler avec la latitude et la longitude stockées sous decimal(7,4)
, je peux faire ceci:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
mais avec geography
, je ferais ceci:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Bien que ce ne soit pas ça beaucoup plus compliqué, pourquoi la complexité add si je n'ai pas?
Avant d'abandonner l'idée d'utiliser geography
, y a-t-il quelque chose que je devrais considérer? Serait-il plus rapide de rechercher un emplacement en utilisant un index spatial plutôt qu'en indexant les champs Latitude et Longitude? Y a-t-il des avantages à utiliser geography
que je ne connais pas? Ou, d'un autre côté, y a-t-il des mises en garde que je devrais savoir et qui me décourageraient d'utiliser geography
?
Mettre à jour
@Erik Philips a évoqué la possibilité d'effectuer des recherches de proximité avec geography
, ce qui est très cool.
D'autre part, un test rapide montre qu'un simple select
pour obtenir la latitude et la longitude est beaucoup plus lent lors de l'utilisation geography
(détails ci-dessous). , et un commentaire sur la réponse acceptée à une autre question SO sur geography
me fait méfier:
@SaphuA De rien. En guise de remarque, soyez TRES prudent d'utiliser un index spatial sur une colonne de type de données GEOGRAPHY Nullable. Il y a un problème de performances sérieux, alors rendez cette colonne GEOGRAPHY non nullable même si vous devez remodeler votre schéma. - Tomas 18 juin à 11:18
Dans l'ensemble, en pesant la probabilité de faire des recherches de proximité par rapport au compromis entre les performances et la complexité, j'ai décidé de renoncer à l'utilisation de geography
dans ce cas.
Détails du test que j'ai effectué:
J'ai créé deux tableaux, l'un utilisant geography
et l'autre utilisant decimal(9,6)
pour la latitude et la longitude:
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)
)
et inséré une seule ligne en utilisant les mêmes valeurs de latitude et de longitude dans chaque tableau:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Enfin, l'exécution du code suivant montre que, sur ma machine, la sélection de la latitude et de la longitude est environ 5 fois plus lente lors de l'utilisation 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
Résultats:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Ce qui était plus surprenant, c'est que même lorsqu'aucune ligne n'est sélectionnée, par exemple sélectionner où RowId = 2
, qui n'existe pas, geography
était encore plus lent:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947
la source
Réponses:
Si vous prévoyez d'effectuer un calcul spatial, EF 5.0 autorise les expressions LINQ telles que:
Ensuite, il y a une très bonne raison d'utiliser la géographie.
Explication du spatial dans Entity Framework .
Mis à jour avec création de bases de données spatiales hautes performances
Comme je l'ai noté sur la réponse de Noel Abraham :
Donc, comparer les types de stockage:
Résultat:
Le type de données géographie occupe 30% d'espace en plus.
De plus, le type de données geography ne se limite pas au stockage d'un point, vous pouvez également stocker LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString et MultiPolygon et plus encore . Toute tentative de stocker même le plus simple des types de géographie (comme Lat / Long) au-delà d'un point (par exemple, LINESTRING (1 1, 2 2) instance) entraînera des lignes supplémentaires pour chaque point, une colonne pour le séquençage pour l'ordre de chaque point et une autre colonne pour le regroupement des lignes. SQL Server propose également des méthodes pour les types de données Géographie qui incluent le calcul de la zone, de la limite, de la longueur, des distances, etc. etc.
Il semble imprudent de stocker la latitude et la longitude sous forme décimale dans Sql Server.
Mise à jour 2
Si vous prévoyez de faire des calculs tels que la distance, la superficie, etc., il est difficile de les calculer correctement sur la surface de la terre. Chaque type de géographie stocké dans SQL Server est également stocké avec un ID de référence spatiale . Ces identifiants peuvent être de différentes sphères (la terre est 4326). Cela signifie que les calculs dans SQL Server seront en fait calculés correctement sur la surface de la Terre (au lieu de voler à vol d'oiseau qui pourrait traverser la surface de la Terre).
la source
geography
et vous en avez fourni quelques-unes. En fin de compte, j'ai décidé de n'utiliser que desdecimal
champs dans ce cas (voir ma longue mise à jour), mais il est bon de savoir que je peux l'utilisergeography
si jamais j'ai besoin de faire quelque chose de plus sophistiqué que de simplement cartographier les coordonnées.Une autre chose à considérer est l'espace de stockage occupé par chaque méthode. Le type de géographie est stocké sous forme de fichier
VARBINARY(MAX)
. Essayez d'exécuter ce script:Résultat:
Le type de données de géographie occupe presque deux fois plus d'espace.
la source
la source