在符合 ANSI SQL 的数据库中存储纬度或经度数据时,哪种数据类型最合适?应该float
使用, or decimal
, or ...?
我知道 Oracle、MySql 和 SQL Server 已经添加了一些专门用于处理地理数据的特殊数据类型,但我对如何将信息存储在“普通”SQL 数据库中感兴趣。
在符合 ANSI SQL 的数据库中存储纬度或经度数据时,哪种数据类型最合适?应该float
使用, or decimal
, or ...?
我知道 Oracle、MySql 和 SQL Server 已经添加了一些专门用于处理地理数据的特殊数据类型,但我对如何将信息存储在“普通”SQL 数据库中感兴趣。
纬度使用:Decimal(8,6)
,经度使用:Decimal(9,6)
如果您不习惯精度和比例参数,这里有一个格式字符串视觉效果:
纬度和经度
##.######
和###.######
精确到小数点后 6 位应该可以让您在坐标上达到约 10 厘米的精度。
我们使用浮点数,但任何带有 6 位小数的数字风格也应该可以使用。
您应该看看 SQL Server 2008 中引入的新 Spatial 数据类型。它们是专门为此类任务设计的,使索引和查询数据更加容易和高效。
http://msdn.microsoft.com/en-us/library/bb933876(v=sql.105).aspx
您可以轻松地将 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 */
我会为您的数据使用具有适当精度的小数。
在 vanilla Oracle 中,称为 LOCATOR(Spatial 的残缺版本)的功能要求使用 NUMBER 数据类型(无精度)存储坐标数据。当您尝试创建基于函数的索引以支持空间查询时,它会作呕。
我认为这取决于您最常需要执行的操作。
如果您需要将完整值作为十进制数,请使用具有适当精度和比例的小数。我相信,浮动远远超出了您的需求。
如果您经常转换到/从 degºmin'sec" 分数表示法,我会考虑将每个值存储为整数类型(smallint、tinyint、tinyint、smallint?)。