Sto ridisegnando un database clienti e una delle nuove informazioni che vorrei memorizzare insieme ai campi dell'indirizzo standard (Via, Città, ecc.) È la posizione geografica dell'indirizzo. L'unico caso d'uso che ho in mente è quello di consentire agli utenti di mappare le coordinate su Google Maps quando l'indirizzo non può essere trovato altrimenti, cosa che spesso accade quando l'area è di nuova costruzione o si trova in una posizione remota / rurale.
La mia prima inclinazione era quella di memorizzare latitudine e longitudine come valori decimali, ma poi mi sono ricordato che SQL Server 2008 R2 ha un geography
tipo di dati. Non ho assolutamente esperienza nell'uso geography
e, dalla mia ricerca iniziale, sembra essere eccessivo per il mio scenario.
Ad esempio, per lavorare con latitudine e longitudine memorizzate come decimal(7,4)
, posso fare questo:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
ma con geography
, lo farei:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Anche se non è che molto più complicato, perché aggiungere complessità se io non devo?
Prima di abbandonare l'idea di utilizzare geography
, c'è qualcosa che dovrei considerare? Sarebbe più veloce cercare una posizione utilizzando un indice spaziale anziché indicizzare i campi Latitudine e Longitudine? Ci sono vantaggi nell'utilizzo di geography
cui non sono a conoscenza? Oppure, il rovescio della medaglia, ci sono avvertenze che dovrei sapere che mi scoraggerebbero dall'uso geography
?
Aggiornare
@Erik Philips ha parlato della possibilità di eseguire ricerche di prossimità geography
, il che è molto interessante.
D'altra parte, un test rapido mostra che un semplice select
per ottenere la latitudine e la longitudine è significativamente più lento quando si utilizza geography
(dettagli di seguito). , e un commento sulla risposta accettata a un'altra domanda SO su geography
mi ha diffidente:
@SaphuA Sei il benvenuto. Come nota a margine, sii MOLTO attento a utilizzare un indice spaziale su una colonna del tipo di dati GEOGRAPHY nullable. Ci sono alcuni seri problemi di prestazioni, quindi rendi quella colonna GEOGRAPHY non annullabile anche se devi rimodellare lo schema. - Tomas, 18 giugno alle 11:18
Tutto sommato, valutando la probabilità di fare ricerche di prossimità rispetto al compromesso in termini di prestazioni e complessità, ho deciso di rinunciare all'uso di geography
in questo caso.
Dettagli del test che ho eseguito:
Ho creato due tabelle, una usando geography
e un'altra usando decimal(9,6)
per latitudine e longitudine:
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)
)
e inserito una singola riga utilizzando gli stessi valori di latitudine e longitudine in ciascuna tabella:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Infine, l'esecuzione del codice seguente mostra che, sulla mia macchina, la selezione della latitudine e della longitudine è circa 5 volte più lenta durante l'utilizzo 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
risultati:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Ciò che è stato più sorprendente è che anche quando non sono state selezionate righe, ad esempio la selezione di dove RowId = 2
, che non esiste, è geography
stata ancora più lenta:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947