[英]What is the ideal data type to use when storing latitude / longitude in a MySQL database?
请记住,我将对纬度/经度对执行计算,哪种数据类型最适合与 MySQL 数据库一起使用?
将 MySQL 的空间扩展与 GIS 结合使用。
基本上,这取决于您所在位置所需的精度。 使用 DOUBLE,您将获得 3.5nm 的精度。 DECIMAL(8,6)/(9,6) 下降到 16cm。 FLOAT 是 1.7m...
这个非常有趣的表有一个更完整的列表: http : //mysql.rjweb.org/doc.php/latlng :
Datatype Bytes Resolution
Deg*100 (SMALLINT) 4 1570 m 1.0 mi Cities
DECIMAL(4,2)/(5,2) 5 1570 m 1.0 mi Cities
SMALLINT scaled 4 682 m 0.4 mi Cities
Deg*10000 (MEDIUMINT) 6 16 m 52 ft Houses/Businesses
DECIMAL(6,4)/(7,4) 7 16 m 52 ft Houses/Businesses
MEDIUMINT scaled 6 2.7 m 8.8 ft
FLOAT 8 1.7 m 5.6 ft
DECIMAL(8,6)/(9,6) 9 16cm 1/2 ft Friends in a mall
Deg*10000000 (INT) 8 16mm 5/8 in Marbles
DOUBLE 16 3.5nm ... Fleas on a dog
希望这可以帮助。
Google 为带有 Google 地图的示例“商店定位器”应用程序提供了一个从头到尾的 PHP/MySQL 解决方案。 在这个例子中,他们将 lat/lng 值存储为“Float”,长度为“10,6”
MySQL 的空间扩展是最好的选择,因为您可以使用完整的空间运算符和索引列表。 空间索引将允许您非常快速地执行基于距离的计算。 请记住,从 6.0 开始,空间扩展仍然不完整。 我不是在贬低 MySQL Spatial,只是在你深入了解它之前让你知道其中的陷阱。
如果您严格处理点并且只处理 DISTANCE 函数,这很好。 如果您需要对多边形、线或缓冲点进行任何计算,除非您使用“相关”运算符,否则空间运算符不会提供准确的结果。 请参阅21.5.6顶部的警告。 包含、内或相交等关系使用的是 MBR,而不是精确的几何形状(即椭圆被视为矩形)。
此外,MySQL Spatial 中的距离与您的第一个几何体的单位相同。 这意味着如果您使用十进制度数,那么您的距离测量值以十进制度数为单位。 当您远离赤道时,这将很难获得准确的结果。
当我为从 ARINC424 构建的导航数据库执行此操作时,我进行了大量测试并回顾了代码,我使用了 DECIMAL(18,12)(实际上是 NUMERIC(18,12),因为它是火鸟)。
浮点数和双精度数不那么精确,可能会导致舍入错误,这可能是一件非常糟糕的事情。 我不记得我是否发现任何有问题的真实数据 - 但我相当肯定无法准确地存储在浮点数或双精度数中可能会导致问题
关键是当使用度数或弧度时,我们知道值的范围 - 小数部分需要最多的数字。
MySQL 空间扩展是一个很好的选择,因为它们遵循OpenGIS 几何模型。 我没有使用它们,因为我需要保持我的数据库可移植。
取决于您需要的精度。
Datatype Bytes resolution
------------------ ----- --------------------------------
Deg*100 (SMALLINT) 4 1570 m 1.0 mi Cities
DECIMAL(4,2)/(5,2) 5 1570 m 1.0 mi Cities
SMALLINT scaled 4 682 m 0.4 mi Cities
Deg*10000 (MEDIUMINT) 6 16 m 52 ft Houses/Businesses
DECIMAL(6,4)/(7,4) 7 16 m 52 ft Houses/Businesses
MEDIUMINT scaled 6 2.7 m 8.8 ft
FLOAT 8 1.7 m 5.6 ft
DECIMAL(8,6)/(9,6) 9 16cm 1/2 ft Friends in a mall
Deg*10000000 (INT) 8 16mm 5/8 in Marbles
DOUBLE 16 3.5nm ... Fleas on a dog
来自: http : //mysql.rjweb.org/doc.php/latlng
总结一下:
DOUBLE
。DECIMAL(8,6)/(9,6)
。 从MySQL 5.7 开始,考虑使用 空间数据类型(SDT),特别是用于存储单个坐标的POINT
。 在 5.7 之前,SDT 不支持索引(表类型为 MyISAM 时的 5.6 除外)。
笔记:
POINT
类时,用于存储坐标的参数顺序必须为POINT(latitude, longitude)
。ST_Distance
) 并确定一个点是否包含在另一个区域内 ( ST_Contains
)。基于这篇 wiki 文章http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy,MySQL中适当的数据类型是 Decimal(9,6),用于将经度和纬度存储在不同的字段中。
使用DECIMAL(8,6)
表示纬度(90 到 -90 度),使用DECIMAL(9,6)
表示经度(180 到 -180 度)。 6 位小数适用于大多数应用程序。 两者都应该“签名”以允许负值。
不需要走多远,根据谷歌地图,最好的是 FLOAT(10,6) for lat 和 lng。
我们将纬度/经度 X 1,000,000 作为 NUMBERS 存储在我们的 oracle 数据库中,以避免双精度舍入错误。
鉴于到小数点后 6 位的纬度/经度精度为 10 厘米,这就是我们所需要的。 许多其他数据库也将纬度/经度存储到小数点后第 6 位。
从一个完全不同和更简单的角度来看:
VARCHAR
),例如:“ -0000.0000001,-0000.000000000000001 ”(35 长度,如果数字超过 7 位十进制数字,则它会被四舍五入) ;google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
通过这种方式,您无需担心索引编号和所有其他与数据类型相关的问题,这些问题可能会破坏您的坐标。
TL; 博士
如果您不在 NASA / 军事部门工作并且不制造飞机导航系统,请使用 FLOAT(8,5)。
要完全回答您的问题,您需要考虑以下几点:
格式
所以答案的第一部分是 - 您可以以应用程序使用的格式存储坐标,以避免不断来回转换并进行更简单的 SQL 查询。
很可能您使用 Google Maps 或 OSM 来显示您的数据,而 GMaps 使用“十进制度数 2”格式。 所以以相同的格式存储坐标会更容易。
精确
然后,您想定义所需的精度。 当然你可以存储像“-32.608697550570334,21.278081997935146”这样的坐标,但是你有没有在导航到点的时候关心毫米? 如果你不是在 NASA 工作,也不是在做卫星、火箭或飞机的轨迹,你应该能达到几米的精度。
常用格式是点后 5 位数字,精度为 50 厘米。
示例:X,21.278081 8和 X,21.278081 9之间有 1cm 的距离。 所以点之后的 7 位数字给你 1/2cm 的精度,点之后的 5 位数字给你 1/2 米的精度(因为不同点之间的最小距离是 1m,所以舍入误差不能超过它的一半)。 对于大多数民用目的,它应该足够了。
度十进制分钟格式(40° 26.767′ N 79° 58.933′ W)为您提供与点后 5 位数字完全相同的精度
节省空间的存储
如果您选择了十进制格式,那么您的坐标是一对 (-32.60875, 21.27812)。 显然,2 x(符号为 1 位,度数为 2 位,指数为 5 位)就足够了。
所以在这里我想从评论中支持Alix Axel ,说 Google 建议将它存储在 FLOAT(10,6) 中确实是额外的,因为主要部分不需要 4 位数字(因为符号是分开的,纬度是有限的到 90,经度限制为 180)。 您可以轻松地使用 FLOAT(8,5) 获得 1/2m 的精度或使用 FLOAT(9,6) 获得 50/2cm 的精度。 或者,您甚至可以将 lat 和 long 存储在分离的类型中,因为 FLOAT(7,5) 对 lat 来说就足够了。 请参阅 MySQL 浮点类型参考。 它们中的任何一个都将像正常的 FLOAT 一样并且等于 4 个字节。
现在空间通常不是问题,但是如果您出于某种原因想要真正优化存储(免责声明:不要进行预优化),您可以压缩 lat(不超过 91 000 个值 + 符号)+ long(不超过 181 000 个值 + 符号)到 21 位,这明显小于2xFLOAT(8 字节 == 64 位)
MySQL 对所有浮点数使用 double ......所以使用 double 类型。 在大多数情况下,使用 float 会导致不可预测的舍入值
虽然它不是所有操作的最佳选择,但如果您正在制作地图图块或使用大量标记(点),只有一个投影(例如墨卡托,如谷歌地图和许多其他滑动地图框架所期望的),我发现了什么我称“巨大坐标系”是为了非常非常方便。 基本上,您以某种放大方式存储 x 和 y 像素坐标——我使用缩放级别 23。这有几个好处:
我在最近的一篇博文中谈到了这一切: http : //blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
根据您的应用程序,我建议使用 FLOAT(9,6)
空间键将为您提供更多功能,但在生产基准中,浮点数比空间键快得多。 (平均 0,01 VS 0,001)
我对某些答案/评论感到非常惊讶。
到底为什么有人愿意自愿“降低”精度,然后在以后对更差的数字进行计算呢? 听起来最终是愚蠢的。
如果源具有64位精度,则自愿将比例固定为例如,这肯定是愚蠢的。 6位小数,并将精度限制为最多9个有效位数(通常建议使用的9.6十进制格式)。
自然地,人们以原始资料所具有的精度来存储数据。 降低精度的唯一原因将是有限的存储空间。
十进制9.6格式会导致捕捉到网格现象。 如果这真的发生的话,那应该是最后一步。
我不会邀请累积的错误来我的巢。
纬度范围从 -90 到 +90(度),因此 DECIMAL(10, 8) 可以
经度范围从 -180 到 +180(度),因此您需要 DECIMAL(11, 8)。
注:第一个数字是存储的总位数,第二个数字是小数点后的数字。
简而言之: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
PostGIS 中的空间函数比 MySQL 空间函数中的函数更实用(即不受 BBOX 操作的限制)。 检查一下:链接文本
我建议您对 SQL Server 使用 Float 数据类型。
存储 Lat Long 值的理想数据类型是 decimal(9,6)
这是大约 10 厘米的精度,同时仅使用 5 个字节的存储空间。
例如 CAST(123.456789 as decimal(9,6))
GeoLocationCoordinates 返回双精度数据类型,以十进制度表示位置的纬度和经度。 您可以尝试使用双。
Lat Long 计算需要精度,因此使用某种类型的十进制类型并使精度至少比您将存储的数字高 2 以执行数学计算。 我不知道我的 sql 数据类型,但在 SQL Server 中,人们经常使用浮点数或实数而不是十进制数并遇到麻烦,因为这些是估计数字而不是实数。 所以只要确保你使用的数据类型是真正的十进制类型而不是浮点十进制类型,你应该没问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.