Estou redesenhando um banco de dados de clientes e uma das novas informações que gostaria de armazenar junto com os campos de endereço padrão (rua, cidade etc.) é a localização geográfica do endereço. O único caso de uso que tenho em mente é permitir que os usuários mapeiem as coordenadas nos mapas do Google quando o endereço não puder ser encontrado de outra forma, o que geralmente acontece quando a área é desenvolvida recentemente ou está em uma localização remota / rural.
Minha primeira inclinação foi armazenar latitude e longitude como valores decimais, mas então me lembrei que o SQL Server 2008 R2 tem um geography
tipo de dados. Não tenho absolutamente nenhuma experiência com o uso geography
e, pela minha pesquisa inicial, parece um exagero para o meu cenário.
Por exemplo, para trabalhar com latitude e longitude armazenadas como decimal(7,4)
, posso fazer o seguinte:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
mas com geography
, eu faria isso:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Embora não seja que muito mais complicado, porque a complexidade add se eu não tem que?
Antes de abandonar a ideia de usar geography
, há algo que devo considerar? Seria mais rápido pesquisar um local usando um índice espacial em vez de indexar os campos Latitude e Longitude? Há vantagens em usar geography
que eu não conheço? Ou, por outro lado, há ressalvas que devo saber que me desencorajariam a usargeography
?
Atualizar
@Erik Philips trouxe a capacidade de fazer pesquisas de proximidade com geography
, o que é muito legal.
Por outro lado, um teste rápido está mostrando que uma forma simples select
de obter a latitude e a longitude é significativamente mais lenta ao usar geography
(detalhes abaixo). , e um comentário sobre a resposta aceita a outra pergunta do SO geography
me deixou desconfiado:
@SaphuA De nada. Como nota lateral, tenha MUITO cuidado ao usar um índice espacial em uma coluna de tipo de dados GEOGRAPHY anulável. Há alguns problemas sérios de desempenho, portanto, torne essa coluna GEOGRAPHY não anulável, mesmo se você precisar remodelar seu esquema. - Tomas 18 de junho às 11h18
Ao todo, pesando a probabilidade de fazer pesquisas de proximidade versus a compensação em desempenho e complexidade, decidi renunciar ao uso de geography
neste caso.
Detalhes do teste que fiz:
Criei duas tabelas, uma usando geography
e outra usando decimal(9,6)
para latitude e 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)
)
e inseriu uma única linha usando os mesmos valores de latitude e longitude em cada tabela:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Finalmente, rodar o código a seguir mostra que, na minha máquina, selecionar a latitude e longitude é aproximadamente 5 vezes mais lento durante o uso 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
Resultados:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
O que foi mais surpreendente é que mesmo quando nenhuma linha foi selecionada, por exemplo, selecionar onde RowId = 2
, que não existe, geography
ainda era mais lento:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947
fonte
Respostas:
Se você planeja fazer qualquer computação espacial, EF 5.0 permite Expressões LINQ como:
Então, há um bom motivo para usar a Geografia.
Explicação de espacial no Entity Framework .
Atualizado com a criação de bancos de dados espaciais de alto desempenho
Como observei na resposta de Noel Abrahams :
Então, comparando os tipos de armazenamento:
Resultado:
O tipo de dados geográficos ocupa 30% mais espaço.
Além disso, o tipo de dados geográficos não se limita apenas ao armazenamento de um Ponto, você também pode armazenar LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString e MultiPolygon e muito mais . Qualquer tentativa de armazenar até mesmo o mais simples dos tipos de geografia (como latitude / longitude) além de um ponto (por exemplo, LINESTRING (1 1, 2 2) instância) incorrerá em linhas adicionais para cada ponto, uma coluna para sequenciamento para a ordem de cada ponto e outra coluna para agrupamento de linhas. O SQL Server também possui métodos para os tipos de dados geográficos que incluem o cálculo de área, limite, comprimento, distâncias e muito mais .
Parece imprudente armazenar Latitude e Longitude como Decimal no Sql Server.
Atualização 2
Se você planeja fazer cálculos como distância, área, etc, calculá-los corretamente sobre a superfície da Terra é difícil. Cada tipo de geografia armazenado no SQL Server também é armazenado com um ID de referência espacial . Esses ids podem ser de esferas diferentes (a terra é 4326). Isso significa que os cálculos no SQL Server irão, na verdade, calcular corretamente sobre a superfície da terra (em vez de como o corvo voa, que poderia ser através da superfície da terra).
fonte
geography
e você forneceu alguns bons. No final das contas, decidi usar apenasdecimal
campos neste caso (veja minha atualização prolixa), mas é bom saber que posso usargeography
se precisar fazer algo mais sofisticado do que simplesmente mapear coordenadas.Outra coisa a se considerar é o espaço de armazenamento ocupado por cada método. O tipo de geografia é armazenado como um
VARBINARY(MAX)
. Tente executar este script:Resultado:
O tipo de dados geográficos ocupa quase o dobro do espaço.
fonte
fonte