351

在符合 ANSI SQL 的数据库中存储纬度或经度数据时,哪种数据类型最合适?应该float使用, or decimal, or ...?

我知道 Oracle、MySql 和 SQL Server 已经添加了一些专门用于处理地理数据的特殊数据类型,但我对如何将信息存储在“普通”SQL 数据库中感兴趣。

4

8 回答 8

535

纬度使用:Decimal(8,6),经度使用:Decimal(9,6)

如果您不习惯精度和比例参数,这里有一个格式字符串视觉效果:

纬度和经度 ##.#########.######

精确到小数点后 6 位应该可以让您在坐标上达到约 10 厘米的精度。

于 2009-07-28T20:07:09.663 回答
10

我们使用浮点数,但任何带有 6 位小数的数字风格也应该可以使用。

于 2009-07-28T20:07:28.007 回答
2

您应该看看 SQL Server 2008 中引入的新 Spatial 数据类型。它们是专门为此类任务设计的,使索引和查询数据更加容易和高效。

http://msdn.microsoft.com/en-us/library/bb933876(v=sql.105).aspx

于 2012-09-05T17:49:17.187 回答
2

好吧,您问如何存储纬度/经度,我的回答是:不要,您可以考虑使用WGS 84(在欧洲ETRS 89),因为它是地理参考的标准。

但是除了这个细节之外,我在 SQL 2008 最终包含地理支持之前的日子里使用了用户定义类型。

于 2009-07-28T21:12:37.457 回答
2

您可以轻松地将 lat/lon 十进制数存储在无符号整数字段中,而不是将它们拆分为整数和小数部分,然后使用以下转换算法将它们分开存储,如这里所建议的那样:

作为存储的mysql函数:

CREATE DEFINER=`r`@`l` FUNCTION `PositionSmallToFloat`(s INT) 
RETURNS decimal(10,7)
DETERMINISTIC
RETURN if( ((s > 0) && (s >> 31)) , (-(0x7FFFFFFF - 
(s & 0x7FFFFFFF))) / 600000, s / 600000)

然后回来

CREATE DEFINER=`r`@`l` FUNCTION `PositionFloatToSmall`(s DECIMAL(10,7)) 
RETURNS int(10)
DETERMINISTIC
RETURN s * 600000

这需要存储在unsigned int(10)中,这适用于 mysql 以及无类型的 sqlite。

通过经验,我发现这工作得非常快,如果你只需要存储坐标并检索这些坐标来做一些数学运算的话。

在 php 中,这两个函数看起来像

function LatitudeSmallToFloat($LatitudeSmall){
   if(($LatitudeSmall>0)&&($LatitudeSmall>>31)) 
     $LatitudeSmall=-(0x7FFFFFFF-($LatitudeSmall&0x7FFFFFFF))-1;
   return (float)$LatitudeSmall/(float)600000;
}

又回来了:

function LatitudeFloatToSmall($LatitudeFloat){
   $Latitude=round((float)$LatitudeFloat*(float)600000);
   if($Latitude<0) $Latitude+=0xFFFFFFFF;
   return $Latitude;
}

这在创建例如带有整数的 memcached 唯一键方面也有一些额外的优势。(例如:缓存地理编码结果)。希望这能增加讨论的价值。

另一个应用程序可能是当您没有 GIS 扩展并且只想保留几百万个纬度/经度对时,您可以在 mysql 中的这些字段上使用分区以受益于它们是整数的事实:

Create Table: CREATE TABLE `Locations` (
  `lat` int(10) unsigned NOT NULL,
  `lon` int(10) unsigned NOT NULL,
  `location` text,
  PRIMARY KEY (`lat`,`lon`) USING BTREE,
  KEY `index_location` (`locationText`(30))
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY KEY ()
PARTITIONS 100 */
于 2012-09-18T15:14:44.703 回答
2

我会为您的数据使用具有适当精度的小数。

于 2009-07-28T20:08:02.047 回答
2

在 vanilla Oracle 中,称为 LOCATOR(Spatial 的残缺版本)的功能要求使用 NUMBER 数据类型(无精度)存储坐标数据。当您尝试创建基于函数的索引以支持空间查询时,它会作呕。

于 2009-08-25T19:24:39.033 回答
1

我认为这取决于您最常需要执行的操作。

如果您需要将完整值作为十进制数,请使用具有适当精度和比例的小数。我相信,浮动远远超出了您的需求。

如果您经常转换到/从 degºmin'sec" 分数表示法,我会考虑将每个值存储为整数类型(smallint、tinyint、tinyint、smallint?)。

于 2009-07-28T20:11:57.873 回答