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

Cod*_*eef 420 mysql mapping maps database-design latitude-longitude

请记住,我将在lat/long对上执行计算,哪种数据类型最适合与MySQL数据库一起使用?

Kir*_*ser 158

使用MySQL的GIS 空间扩展.

  • 您是否有任何其他链接到示例或任何其他信息,以了解如何最好地开始使用它们? (22认同)
  • MYSQL Spatial是一个不错的选择,但仍然有很大的限制和警告(截至6).请看下面我的答案...... (6认同)

Ted*_*ery 147

谷歌为使用谷歌地图的"商店定位器"应用程序提供了一个开始完成PHP/MySQL解决方案.在此示例中,它们将lat/lng值存储为"Float",长度为"10,6"

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

  • @AlixAxel我认为谷歌知道它在做什么.因为它指出:"_With谷歌地图目前的缩放能力,您只需要精确6位数字的小数点后这将让域存储小数点后6位数字,以及多达4位小数之前,如*.*-123.456789**degrees._".如果选中无符号,则模式将为**1234,567890**.所以没问题. (36认同)
  • @AlixAxel他正在计算序列中的数字; 不使用实际坐标... (16认同)
  • Google显然不了解FLOAT规范的工作原理:`FLOAT(10,6)`为坐标的整数部分留下4位数.不,符号不计 - 来自(未)签名属性. (11认同)
  • 使用Laravel的数据类型"Double" (8认同)
  • 但是如果你需要存储来自[0,180]的整数部分值应该更加足够,对吧? (2认同)

Sim*_*mon 125

基本上,它取决于您所在位置所需的精度.使用DOUBLE,你将拥有3.5nm的精度.DECIMAL(8,6)/(9,6)下降到16cm.FLOAT是1.7米......

这个非常有趣的表有一个更完整的列表: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
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 我需要针对帖子的内容写一篇建设性的详细评论,所以我要说的是,在观察Rick James网站提供的准确度表的同时,我对解决方案描述“狗跳蚤”感到很高兴,并且感到值得荣誉。从技术上讲,这是一个有用的描述,它帮助我决定了在存储用于测量两个地址之间距离的坐标时要使用哪种数据类型,@ Simon,感谢您的分享。 (2认同)
  • 要在这里回答我自己的问题,我猜他们已经将每种类型的字节数增加了一倍,以考虑纬度+经度(即“2个双精度== 16个字节”)。 (2认同)

Jam*_*hek 74

MySQL的Spatial Extensions是最佳选择,因为您可以使用空间运算符和索引的完整列表.空间索引将允许您非常快速地执行基于距离的计算.请记住,从6.0开始,Spatial Extension仍然不完整.我没有放下MySQL Spatial,只是在你对这个问题做出太多分析之前让你知道陷阱.

如果您严格处理积分并且只处理DISTANCE功能,那么这很好.如果需要使用"多边形","线"或"缓冲点"进行任何计算,则除非使用"关联"运算符,否则空间运算符不会提供精确结果.请参阅21.5.6顶部的警告.诸如包含,内部或相交之类的关系使用MBR,而不是精确的几何形状(即椭圆被视为矩形).

此外,MySQL Spatial中的距离与第一个几何体的距离相同.这意味着如果您使用十进制度数,则您的距离测量值为十进制度数.这将使你很难得到准确的结果,因为你从赤道得到了更好的结果.

  • 重述:MySQL Spatial Extensions不适合计算由lat/long表示的地球表面上的点之间的大圆距离.它们的距离函数等仅适用于笛卡尔坐标,平面坐标. (26认同)
  • 上面的评价很高的笔记现在似乎已经过时了几年。从 mysql 5.7 开始,有 `ST_Distance_Sphere` 可以做到这一点。 (3认同)

Ric*_*son 70

当我为ARINC424构建的导航数据库执行此操作时,我进行了大量测试并回顾了代码,我使用了DECIMAL(18,12)(实际上是NUMERIC(18,12)因为它是firebird).

浮点数和双打数据并不精确,可能会导致舍入错误,这可能是一件非常糟糕的事情.我不记得我是否发现任何有问题的真实数据 - 但我相当确定无法准确存储在浮点数或双数据中可能会导致问题

关键是当使用度数或弧度时,我们知道值的范围 - 并且小数部分需要最多的数字.

MySQL中的空间扩展是一个很好的选择,因为他们遵循的开放GIS几何模型.我没有使用它们,因为我需要保持数据库的可移植性.

  • 谢谢,这很有帮助.从2008年开始意识到它已经是8年前的所有这些问题和答案,感觉很奇怪. (3认同)
  • @TheSexiestManinJamaica - 在 IEEE 754-1985 之前,计算机浮点硬件是混乱的。甚至在机器上,“a*b”不等于“b*a”(对于某些值)。有很多类似这样的例子:“2+2 = 3.9999”。该标准清理了很多混乱,并被几乎所有硬件和软件“迅速”采用。因此,这场讨论不仅自 2008 年以来一直有效,而且已经持续了三分之一个世纪。 (3认同)

Gaj*_*jus 41

取决于您需要的精度.

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
Run Code Online (Sandbox Code Playgroud)

来自:http://mysql.rjweb.org/doc.php/latlng

总结一下:

  • 最精确的选择是DOUBLE.
  • 最常见的类型是DECIMAL(8,6)/(9,6).

MySQL 5.7开始,考虑使用空间数据类型(SDT),专门POINT用于存储单个坐标.在5.7之前,SDT不支持索引(当表类型为MyISAM时,5.6除外).

注意:

  • 使用POINTclass时,存储坐标的参数顺序必须是POINT(latitude, longitude).
  • 有一种用于创建空间索引的特殊语法.
  • 使用SDT的最大好处是您可以访问空间分析功能,例如计算两点之间的距离(ST_Distance)并确定一个点是否包含在另一个区域内(ST_Contains).

  • 对狗的精确跳蚤的upvote! (3认同)
  • 你复制上一个答案的粘贴部分,并用创建该表**的人**推荐的东西"总结"**:«如何分区?好吧,MySQL非常挑剔.所以FLOAT/DOUBLE出局了.DECIMAL已经结束了.所以,我们坚持一些kludge.基本上,我们需要将Lat/Lng转换为某个大小的INT并使用PARTITION BY RANGE.»和«FLOAT有24个有效位; DOUBLE有53.(它们不适用于PARTITIONing但是为了完整而包括在内.**通常人们使用DOUBLE而没有意识到它是多大的**,以及需要多少空间.)»只需离开SDT部分你中写道. (2认同)
  • 不,他没有从你那里复制,他只是像你在 2014 年引用的链接(你的帖子是 2015 年的)一样粘贴了表格。顺便说一句,我认为您在链接 **Spatial** 数据类型时拼错了“Special”。如果您添加更多示例,例如“CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;”以及有关 SDT 限制的警告,您编写的这部分实际上对想要开始使用它们的人很有用,正如 [James 提到的](http://stackoverflow.com/a/163084/1326147),也许您的回答在帮助其他人方面也会更加简洁和准确...... (2认同)

sae*_*jad 33

基于这篇wiki文章 http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy,MySQL中 的相应数据类型是Decimal(9,6),用于将经度和纬度存储在单独的字段中.


Ale*_*ove 19

使用DECIMAL(8,6)纬度(90至-90度)和DECIMAL(9,6)经度(180〜-180度).对于大多数应用程序,小数点后6位.两者都应该"签名"以允许负值.

  • @Kondybas - 由于数据库中的主要成本是获取行,因此不应担心浮点数和小数点之间的性能差异。 (2认同)

Mar*_*dor 14

根据谷歌地图,没有必要走远,最好的是lat和lng的FLOAT(10,6).

  • @webfacer,看起来从“mysql 8.0.17”开始,“FLOAT”语法已被弃用。Mysql 现在建议仅使用“FLOAT”,不带任何精度参数 https://dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html 和 https://dev.mysql.com/doc /refman/5.5/en/floating-point-types.html (4认同)
  • @webfacer,它位于“在 MySQL 中创建表”部分:https://developers.google.com/maps/documentation/javascript/mysql-to-maps 例如 `lat FLOAT( 10, 6 ) NOT NULL,` `lng FLOAT( 10, 6 ) NOT NULL` (3认同)

小智 7

我们将oracle数据库中的纬度/经度X 1,000,000存储为NUMBERS,以避免双打出现错误.

鉴于小数点后第6位的纬度/经度是10厘米精度,这就是我们所需要的.许多其他数据库也将lat/long存储到第6个小数位.

  • 如果你有大量数据,乘以一些大数字(如一百万)是很好的,因为整数运算(例如索引检索)比浮点数快得多. (2认同)

Arm*_*oot 6

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

  • 如果您依靠Google来显示您的地图,标记,多边形等等,那么请让Google完成计算!
  • 您可以在服务器上保存资源,只需将纬度和经度一起存储为单个字符串(VARCHAR),例如:" - 0000.0000001,-0000.000000000000001 "(长度为35,如果数字的小数位数超过7位则会被舍入);
  • 如果谷歌每个号码返回的小数位数超过7位数,那么无论如何你都可以将这些数据存储在你的字符串中,以防你以后想要检测一些逃亡或微生物 ;
  • 你可以使用它们的距离矩阵或它们的几何库来计算某些区域的距离或检测点,调用就像这样简单:google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • 您可以使用许多"服务器端"API(使用Google Maps API,使用Python,Ruby on Rails,PHP,CodeIgniter,Laravel,Yii,Zend Framework等).

这样您就不必担心索引数字以及与数据类型相关的所有其他问题,这些问题可能会破坏您的坐标.

  • @Yarin这是一个很受欢迎的问题,其中一些(或很多)人只需要根据自己的需求来解答如何存储坐标(很多人可能只使用Google地图).你的downvote暗示这个答案可能无法帮助他们......通过将坐标存储在一个字符串中,他们将确切地知道提供给他们的原始值(例如:Google),如果他们决定进化他们的话,他们会在以后帮助他们自己的应用程序并对它们执行计算.那时,他们仍然会拥有原始的原始数据,因为他们没有弄乱转换. (4认同)

mah*_*fuz 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


Kai*_*ood 5

虽然它不是所有操作的最佳选择,但如果您正在制作地图图块或仅使用一个投影来处理大量标记(点)(例如墨卡托,如 Google 地图和许多其他滑地图框架所期望的),我发现了什么我称“庞大坐标系”非常非常方便。基本上,您以某种放大方式存储 x 和 y 像素坐标——我使用缩放级别 23。这有几个好处:

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

我在最近的一篇博客文章中讨论了这一切: http://blog.webfoot.com/2013/03/12/optimizing-map-tile- Generation/


The*_*her 5

TL; 博士

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


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

格式

  • 度分秒:40°26?46?N 79° 58?56?宽
  • 度十进制分:40° 26.767? N 79° 58.933?宽
  • 十进制度 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说谷歌建议将它存储在 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 位)

  • 不仅仅是 NASA 需要高精度。土木工程师和建筑商也需要它,否则你会在停车场和建筑物中遇到大水坑,所有弹珠都会滚到角落里。但测量员并不依赖标准的手机级 GPS。对于标准 GPS,FLOAT(IEEE488 32 位浮点格式)具有足够的精度。 (2认同)