Estoy rediseñando una base de datos de clientes y una de las nuevas piezas de información que me gustaría almacenar junto con los campos de dirección estándar (calle, ciudad, etc.) es la ubicación geográfica de la dirección. El único caso de uso que tengo en mente es permitir que los usuarios mapeen las coordenadas en los mapas de Google cuando la dirección no se puede encontrar de otra manera, lo que a menudo ocurre cuando el área se desarrolla recientemente o se encuentra en una ubicación remota / rural.
Mi primera inclinación fue almacenar la latitud y la longitud como valores decimales, pero luego recordé que SQL Server 2008 R2 tiene un geography
tipo de datos. No tengo absolutamente ninguna experiencia en el uso geography
, y desde mi investigación inicial, parece exagerado para mi escenario.
Por ejemplo, para trabajar con la latitud y la longitud almacenadas como decimal(7,4)
, puedo hacer esto:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
pero con geography
, haría esto:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Aunque no es que mucho más complicado, ¿por qué añadir complejidad si yo no tengo que?
Antes de abandonar la idea de usar geography
, ¿hay algo que deba considerar? ¿Sería más rápido buscar una ubicación utilizando un índice espacial en lugar de indexar los campos de latitud y longitud? ¿Hay ventajas de usar de las geography
que no tenga conocimiento? O, por otro lado, ¿hay advertencias que debería conocer y que me desanimarían a consumir geography
?
Actualizar
@Erik Philips mencionó la capacidad de realizar búsquedas de proximidad con geography
, lo cual es muy bueno.
Por otro lado, una prueba rápida muestra que un simple select
obtener la latitud y la longitud es significativamente más lento cuando se usa geography
(detalles a continuación). , y un comentario sobre la respuesta aceptada a otra pregunta SO geography
me tiene receloso:
@SaphuA De nada. Como nota al margen, tenga MUCHO cuidado al usar un índice espacial en una columna de tipo de datos GEOGRAPHY anulable. Hay algunos problemas graves de rendimiento, por lo que debe hacer que la columna GEOGRAPHY no acepte nulos incluso si tiene que remodelar su esquema. - Tomas 18 de junio a las 11:18
Con todo, al sopesar la probabilidad de realizar búsquedas de proximidad frente a la compensación en rendimiento y complejidad, he decidido renunciar al uso de geography
en este caso.
Detalles de la prueba que realicé:
Creé dos tablas, una usando geography
y otra usando decimal(9,6)
para latitud y longitud:
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 insertó una sola fila usando los mismos valores de latitud y longitud en cada tabla:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Finalmente, ejecutar el siguiente código muestra que, en mi máquina, seleccionar la latitud y la longitud es aproximadamente 5 veces más lento cuando se usa 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
Lo que fue más sorprendente es que incluso cuando no se seleccionan filas, por ejemplo, seleccionar dónde RowId = 2
, que no existe, geography
fue aún más lento:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947
fuente
Respuestas:
Si planea realizar cualquier cálculo espacial, EF 5.0 permite expresiones LINQ como:
Entonces hay una muy buena razón para usar Geografía.
Explicación de espacial dentro de Entity Framework .
Actualizado con la creación de bases de datos espaciales de alto rendimiento
Como señalé en la respuesta de Noel Abrahams :
Entonces, comparando los tipos de almacenamiento:
Resultado:
El tipo de datos geográficos ocupa un 30% más de espacio.
Además, el tipo de datos geográficos no se limita a almacenar solo un punto, también puede almacenar LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString y MultiPolygon y más . Cualquier intento de almacenar incluso los tipos de geografía más simples (como Lat / Long) más allá de un Punto (por ejemplo, LINESTRING (1 1, 2 2) instancia) incurrirá en filas adicionales para cada punto, una columna para secuenciar el orden de cada punto y otra columna para agrupación de líneas. SQL Server también tiene métodos para los tipos de datos de geografía que incluyen el cálculo de Área, Límite, Longitud, Distancias y más .
No parece prudente almacenar la latitud y la longitud como decimal en Sql Server.
Actualización 2
Si planeas hacer cálculos como distancia, área, etc., es difícil calcularlos correctamente sobre la superficie de la tierra. Cada tipo de geografía almacenado en SQL Server también se almacena con un ID de referencia espacial . Estos id pueden ser de diferentes esferas (la tierra es 4326). Esto significa que los cálculos en SQL Server en realidad se calcularán correctamente sobre la superficie de la tierra (en lugar de en línea recta que podría ser a través de la superficie de la tierra).
fuente
geography
y usted proporcionó algunas buenas. En última instancia, decidí usardecimal
campos en este caso (vea mi actualización extensa), pero es bueno saber que puedo usargeography
si alguna vez necesito hacer algo más elegante que simplemente mapear coordenadas.Otro aspecto a considerar es el espacio de almacenamiento que ocupa cada método. El tipo de geografía se almacena como
VARBINARY(MAX)
. Intente ejecutar este script:Resultado:
El tipo de datos geográficos ocupa casi el doble de espacio.
fuente
fuente