我正在重新设计一个客户数据库,其中一个新的信息,我想存储与标准地址字段(街道,城市等)是地址的地理位置。我想到的唯一一个用例是允许用户在谷歌地图上找不到地址时绘制坐标,这种情况通常发生在该地区刚开发或位于偏远/农村地区时。
我的第一个倾向是将经纬度存储为十进制值,但后来我想起了 SQL Server 2008 r2有一个 geography
数据类型。我完全没有使用 geography
的经验,而且从我最初的研究来看,它对于我的场景来说似乎有些过头了。
例如,要处理存储为 decimal(7,4)
的经纬度,我可以这样做:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
但对于 geography
,我会这样做:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
虽然它不是 那个更复杂,为什么要增加复杂性,如果我不必?
在我放弃使用 geography
的想法之前,有什么是我应该考虑的吗?使用空间索引搜索位置是否比索引经纬度字段更快?使用 geography
是否有我不知道的优点?或者,从另一方面来说,我应该知道哪些警告会阻止我使用 geography
?
@ Erik Philips 提出了使用 geography
进行近距离搜索的能力,非常酷。
另一方面,一个快速测试显示,使用简单的 select
获得经纬度的速度明显慢于使用 geography
(详情见下文)。对于 geography
上另一个 SO 问题的评论让我感到疑惑:
@ SaphuA 不客气 可空的 GEOGRAPHY 数据类型列上的空间索引 严重的性能问题,因此使该 GEOGRAPHY 列不为空 即使你不得不重塑你的模式。——托马斯6月18日11:18
总而言之,权衡进行近距离搜索的可能性与在性能和复杂性方面的权衡,我决定在这种情况下放弃使用 geography
。
我运行的测试的细节:
我创建了两个表,一个使用 geography
,另一个使用 decimal(9,6)
经纬度:
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)
)
并在每个表中插入一行使用相同的经纬度值:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
最后,运行以下代码显示,在我的机器上,使用 geography
选择经纬度大约要慢5倍。
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
结果:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
更令人惊讶的是,即使没有选择任何行,例如选择不存在的 RowId = 2
的位置,geography
仍然比较慢:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947