繁体   English   中英

在 MySQL 数据库中存储纬度/经度时,理想的数据类型是什么?

[英]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”

http://code.google.com/apis/maps/articles/phpsqlsearch.html

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)
  • 创建空间索引有一种特殊的语法。
  • 使用 SDT 的最大好处是您可以访问空间分析函数,例如计算两点之间的距离 ( 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 位。

从一个完全不同和更简单的角度来看:

  • 如果您依赖 Google 来显示您的地图、标记、多边形等等,那么让 Google 来完成计算吧!
  • 您可以在服务器上节省资源,只需将纬度和经度存储为单个字符串( VARCHAR ),例如:“ -0000.0000001,-0000.000000000000001 ”(35 长度,如果数字超过 7 位十进制数字,则它会被四舍五入) ;
  • 如果 Google 返回的每个数字超过 7 位十进制数字,您无论如何都可以将该数据存储在您的字符串中,以防万一您想在将来检测到一些逃逸或微生物
  • 你可以使用他们的距离矩阵或他们的几何库来计算距离或检测某些区域的点,调用就像这样简单: google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • 您可以使用大量使用 Google Maps API 的“服务器端”API(在PythonRuby on RailsPHPCodeIgniterLaravelYiiZend Framework等中)。

通过这种方式,您无需担心索引编号和所有其他与数据类型相关的问题,这些问题可能会破坏您的坐标。

TL; 博士

如果您不在 NASA / 军事部门工作并且不制造飞机导航系统,请使用 FLOAT(8,5)。


要完全回答您的问题,您需要考虑以下几点:

格式

  • 度分秒:40° 26′ 46″ N 79° 58′ 56″ W
  • 十进制分: 40° 26.767′ N 79° 58.933′ W
  • 十进制度 1 : 40.446° N 79.982° W
  • 十进制度数 2 : -32.60875, 21.27812
  • 其他一些自制格式? 没有人禁止您制作自己的以家为中心的坐标系,并将其存储为与您家的航向和距离。 这对于您正在处理的某些特定问题可能有意义。

所以答案的第一部分是 - 您可以以应用程序使用格式存储坐标,以避免不断来回转换并进行更简单的 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。这有几个好处:

  • 您对墨卡托像素进行一次昂贵的纬度/经度变换,而不是每次处理该点时
  • 从给定缩放级别的记录中获取图块坐标需要右移一次。
  • 从记录中获取像素坐标需要一次右移和一次按位与。
  • 移位是如此轻量级,以至于在 SQL 中执行它们是可行的,这意味着您可以执行 DISTINCT 以仅返回每个像素位置的一条记录,这将减少后端返回的记录数量,这意味着更少的处理前端。

我在最近的一篇博文中谈到了这一切: 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格式会导致捕捉到网格现象。 如果这真的发生的话,那应该是最后一步。

我不会邀请累积的错误来我的巢。

  1. 纬度范围从 -90 到 +90(度),因此 DECIMAL(10, 8) 可以

  2. 经度范围从 -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 中,人们经常使用浮点数或实数而不是十进制数并遇到麻烦,因为这些是估计数字而不是实数。 所以只要确保你使用的数据类型是真正的十进制类型而不是浮点十进制类型,你应该没问题。

FLOAT应该为您提供所需的所有精度,并且比将每个坐标存储为字符串等更适合比较函数。

如果您的 MySQL 版本早于 5.0.3,您可能需要注意某些浮点比较错误

在 MySQL 5.0.3 之前,DECIMAL 列以精确精度存储值,因为它们表示为字符串,但对 DECIMAL 值的计算是使用浮点运算完成的。 从 5.0.3 开始,MySQL 以 64 位十进制数字的精度执行 DECIMAL 运算,这应该可以解决最常见的 DECIMAL 列的不准确问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM