为什么使用 SQL Server 2008 地理数据类型?

2024-06-19

我正在重新设计客户数据库,我想要与标准地址字段(街道、城市等)一起存储的新信息之一是地址的地理位置。我想到的唯一用例是,当无法找到地址时,允许用户在 Google 地图上绘制坐标,这种情况通常发生在该地区是新开发的或位于偏远/农村地区时。

我的第一个倾向是将纬度和经度存储为十进制值,但后来我想起 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

虽然不是that更复杂,如果不需要的话为什么要增加复杂性呢?

在我放弃使用的想法之前geography,有什么我应该考虑的吗?使用空间索引搜索位置是否比索引纬度和经度字段更快?使用有什么优点吗geography我不知道吗?或者,另一方面,是否有一些我应该知道的警告,这些警告会阻止我使用geography?


Update

@Erik Philips 提出了进行邻近搜索的能力geography,这非常酷。

另一方面,快速测试表明,一个简单的select使用时获取纬度和经度明显较慢geography(详情如下)。 ,以及对接受的答案 https://stackoverflow.com/questions/6386577/sql-server-2008-r2-geography-distance/6387558#6387558到另一个SO问题geography让我怀疑:

@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)

最后,运行以下代码表明,在我的机器上,使用时选择纬度和经度大约慢 5 倍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

Results:

GeographyDuration LatLongDuration
----------------- ---------------
5146              1020
5143              1016
5169              1030

AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152                 1022

更令人惊讶的是,即使没有选择任何行,例如选择 whereRowId = 2,不存在,geography仍然较慢:

GeographyDuration LatLongDuration
----------------- ---------------
1607              948
1610              946
1607              947

AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608                 947

如果您计划进行任何空间计算,EF 5.0 允许使用 LINQ 表达式,例如:

private Facility GetNearestFacilityToJobsite(DbGeography jobsite)
{   
    var q1 = from f in context.Facilities            
             let distance = f.Geocode.Distance(jobsite)
             where distance < 500 * 1609.344     
             orderby distance 
             select f;   
    return q1.FirstOrDefault();
}

那么使用地理就有一个很好的理由。

实体框架内空间的解释 http://msdn.microsoft.com/en-us/data/hh859721.aspx.

更新为创建高性能空间数据库 http://sqlbits.com/Sessions/Event5/creating_high_performance_spatial_databases

正如我所指出的诺埃尔·亚伯拉罕的回答 https://stackoverflow.com/a/10951302/209259:

注意空间,每个坐标都存储为 64 位(8 字节)长的双精度浮点数,8 字节二进制值大致相当于 15 位十进制精度,因此比较十进制(9 ,6) 只有 5 个字节,这并不是一个公平的比较。对于每个 LatLong(总共 18 个字节),Decimal 必须至少为 Decimal(15,12)(9 个字节)才能进行实际比较。

因此比较存储类型:

CREATE TABLE dbo.Geo
(    
geo geography
)
GO

CREATE TABLE dbo.LatLng
(    
    lat decimal(15, 12),   
    lng decimal(15, 12)
)
GO

INSERT dbo.Geo
SELECT geography::Point(12.3456789012345, 12.3456789012345, 4326) 
UNION ALL
SELECT geography::Point(87.6543210987654, 87.6543210987654, 4326) 

GO 10000

INSERT dbo.LatLng
SELECT  12.3456789012345, 12.3456789012345 
UNION
SELECT 87.6543210987654, 87.6543210987654

GO 10000

EXEC sp_spaceused 'dbo.Geo'

EXEC sp_spaceused 'dbo.LatLng'

Result:

name    rows    data     
Geo     20000   728 KB   
LatLon  20000   560 KB

地理数据类型多占用 30% 的空间。

另外,地理数据类型不仅限于存储点,还可以存储LineString、CircularString、CompoundCurve、Polygon、CurvePolygon、GeometryCollection、MultiPoint、MultiLineString 和 MultiPolygon 等 http://technet.microsoft.com/en-us/library/bb933790.aspx。任何尝试存储超出点(例如 LINESTRING(1 1, 2 2) 实例)的最简单的地理类型(如纬度/经度)都会为每个点带来额外的行,以及用于对每个点的顺序进行排序的列另一列用于对行进行分组。 SQL Server 还具有用于地理数据类型的方法,其中包括计算面积、边界、长度、距离等 http://technet.microsoft.com/en-us/library/bb933917.aspx.

在 Sql Server 中将纬度和经度存储为十进制似乎是不明智的。

Update 2

如果您打算进行距离、面积等任何计算,那么在地球表面上正确计算这些内容是很困难的。 SQL Server 中存储的每个地理类型也存储有一个空间参考 ID http://en.wikipedia.org/wiki/SRID。这些 id 可以属于不同的球体(地球是 4326)。这意味着 SQL Server 中的计算实际上将在地球表面上正确计算(而不是乌鸦飞翔 http://en.wikipedia.org/wiki/As_the_crow_flies可能穿过地球表面)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么使用 SQL Server 2008 地理数据类型? 的相关文章

  • 而不是SQL Server中的触发器丢失SCOPE_IDENTITY?

    我有一个表 我在其中创建了一个INSTEAD OF触发执行一些业务规则 问题是当我将数据插入该表时 SCOPE IDENTITY 返回一个NULL值 而不是实际插入的身份 插入 范围代码 INSERT INTO dbo Payment Da
  • 根据纬度/经度获取两点之间的距离

    我尝试实施该公式根据纬度和经度查找距离 http andrew hedges name experiments haversine 该小程序对我正在测试的两点有好处 然而我的代码不起作用 from math import sin cos s
  • “'OFFSET'附近的语法不正确”将sql comm 2012修改为2008

    我用这个列出问题 SELECT q qTitle q qDescription q qCreatedOn u uCode u uFullname qcat qcatTitle q qId q qStatus FROM tblQuestion
  • 谷歌地图 API 的替代品 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • 单元测试定位服务

    我有一个位置跟踪服务 正在尝试对其进行单元测试 我正在尝试使用 locationManager addTestProvider 和 setTestProviderLocation 方法来实现此目的 但是 我似乎无法通过提供程序获取任何位置并
  • 对存储过程内容的只读访问

    是否可以设置 SQL Server 来为开发人员提供对生产数据库上存储过程内容的只读访问权限 您可以授予他们VIEW DEFINITION这些进程的特权 See here http msdn microsoft com en us libr
  • 随机分配工作地点,每个地点不得超过指定员工人数

    我正在尝试在位置列表中选择唯一的随机发布 招聘员工位置 所有员工都已发布在这些位置 我正在尝试为他们生成一个新的随机发布位置 其 位置 条件为 员工新 随机位置将不等于他们的家乡 并且随机选择的员工及其职称必须小于或等于 地点 表中的 地点
  • SQL Server 将一个表中的所有行复制到另一个表中,即重复表

    我想保留一张桌子作为历史并用空桌子替换它 我如何通过 Management Studio 执行此操作 将您的表复制到要存档的表中 SELECT INTO ArchiveTable FROM MyTable 删除表中的所有条目 DELETE
  • Visual Studio 2010 中的数据库设计器

    我需要创建一个全新的 Sql Server 2008 数据库 并希望使用 Visual Studio 2010 Ultimate 中的数据库项目 我已经创建了该项目并在下面添加了一个表格dbo架构 桌子 sql仅以纯文本形式显示 但带有颜色
  • SQL 2008全文索引填充延迟

    我的经理说 在基础表数据更改后 可能需要一段时间才能更新全文搜索索引 例如 如果我有一张桌子Products有一个柱子Description我更新了该描述 然后我可能需要一些时间才能搜索该新描述 真的吗 这需要多长时间 SQL 2008 对
  • 通知设置的数据库设计

    用户可以打开或关闭 他的通知设置 帐户 用于通知 例如 更改帐户资料信息 收到新消息等 通知可以通过电子邮件或手机 推送或短信 发送 用户可以只有 1 封电子邮件和多个手机设备 有什么方法可以改进以下数据库设计或者您会采取不同的方式吗 让我
  • 基于多个表的数据更新单个表 SQL Server 2005,2008

    我需要更新表one使用表中的数据two 表一和表二没有任何公共列相关 桌子three与表相关two 例如 表一 reg det 表 reg det id reg id results 101 11 344 表二 临时表 venue resu
  • 将 Woocommerce 商店变成地理定位国家/地区的目录?

    我正在尝试将我的 woocommerce 商店转变为目录模式 取决于国家 地区 我只想在美国显示产品的价格并添加到购物车功能 我试图通过使用一个名为 的插件来实现这一点GeoIP检测 https wordpress org plugins
  • 用户“xxx”登录失败无法打开显式指定的数据库解决办法

    我首先使用实体 框架代码 启动应用程序时 应用程序尝试在 SQLServer2008R2 上创建数据库 我收到的错误消息是 用户 NT instans Networkservice 登录失败 无法打开明确指定的数据库 更仔细地查看 SQLS
  • com.microsoft.sqlserver.jdbc.SQLServerException:不支持“variant”数据类型

    我想创建显示 MSSQL 服务器版本的简单 Java 代码 public void testMSSQLVersion throws Exception System out println nTesting SQL query for MS
  • 在react.js 中的 componentDidMount() 中执行 fetch 之前,如何通过 navigator.geolocation 获取用户的位置?

    我尝试过多种不同的方法 但我被难住了 不熟悉如何在 React 中使用 Promise 和进行 api 调用 这就是我现在所拥有的 import React Component from react import Column from C
  • SQL Server 2008-获取表约束

    你能帮我构建一个查询 检索所有表中的约束 每个表中的约束计数 并显示NULL对于没有任何约束的表 这是我到目前为止所拥有的 Select SysObjects Name As Constraint Name Tab Name as Tabl
  • 连接别名计算列中的行

    我有两张表 一张名为 Car 一张名为 Mileage 汽车表有以下列 CarName varchar max 里程表有以下列 CarMileage int CarName varchar max TotalGasTrips int 我的代
  • 在eclipse java项目中加载dll文件

    我正在尝试添加文件sqljdbc auth dll到项目库 我将包含 dll 的文件夹添加为外部类文件夹 在这里 我基本上尝试使用 Microsoft 提供的 SQL 驱动程序连接到我的 SQL SERVER 2008 数据库 我的代码是
  • 从批处理文件执行 SQL Server 脚本

    我有一个需要使用批处理文件执行的脚本 我是否在批处理文件中使用 SQLCMD 来运行脚本 此外 该脚本还将数据插入到数据库中的表中 我应该如何格式化批处理文件中的 SQLCMD 以便它知道它应该使用哪个数据库 首先 将查询保存到 sql 文

随机推荐