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