请记住,我将在纬度/经度对上执行计算,哪种数据类型最适合与 MySQL 数据库一起使用?
基本上,这取决于您的位置所需的精度。使用 DOUBLE,您将获得 3.5nm 的精度。 DECIMAL(8,6)/(9,6) 下降到 16 厘米。 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
希望这可以帮助。
将 MySQL 的 spatial extensions 与 GIS 一起使用。
Google 为带有 Google Maps 的示例“Store Locator”应用程序提供了一个从头到尾的 PHP/MySQL 解决方案。在此示例中,它们将 lat/lng 值存储为“Float”,长度为“10,6”
http://code.google.com/apis/maps/articles/phpsqlsearch.html
FLOAT(10,6)
为坐标的整数部分留下 4 位数字。不,符号不算数 - 它来自 (un)signed 属性。
Double
MySQL 的 Spatial Extensions 是最佳选择,因为您可以使用空间运算符和索引的完整列表。空间索引将允许您非常快速地执行基于距离的计算。请记住,从 6.0 开始,空间扩展仍然不完整。我不是在贬低 MySQL Spatial,只是让你在你在这方面走得太远之前知道其中的陷阱。
如果您严格处理点并且只处理 DISTANCE 函数,这很好。如果您需要使用多边形、线或缓冲点进行任何计算,除非您使用“相关”运算符,否则空间运算符不会提供准确的结果。请参阅 21.5.6 顶部的警告。包含、内部或相交等关系使用的是 MBR,而不是确切的几何形状(即,椭圆被视为矩形)。
此外,MySQL Spatial 中的距离与您的第一个几何图形的单位相同。这意味着如果您使用十进制度,那么您的距离测量值是十进制度。当您远离赤道时,这将很难获得准确的结果。
ST_Distance_Sphere
可以做到这一点。
当我为从 ARINC424 构建的导航数据库执行此操作时,我进行了大量测试并回顾代码,我使用了 DECIMAL(18,12)(实际上是 NUMERIC(18,12),因为它是 firebird)。
浮点数和双精度数不那么精确,可能会导致舍入错误,这可能是一件非常糟糕的事情。我不记得我是否发现任何有问题的真实数据 - 但我相当肯定无法准确存储在浮点数或双精度数中可能会导致问题
关键是,当使用度数或弧度时,我们知道值的范围——小数部分需要最多的数字。
MySQL Spatial Extensions 是一个不错的选择,因为它们遵循 The OpenGIS Geometry Model。我没有使用它们,因为我需要保持我的数据库可移植。
a*b
不等于 b*a
的机器上(对于某些值)。有很多例子有点像:2+2 = 3.9999
。该标准清理了很多混乱,并被几乎所有硬件和软件“迅速”采用。因此,这种讨论是有效的,不仅从 2008 年开始,而且持续了三分之一个世纪。
取决于您需要的精度。
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 开始,考虑使用 Spatial Data Types (SDT),特别是 POINT
来存储单个坐标。在 5.7 之前,SDT 不支持索引(表类型为 MyISAM 时,5.6 除外)。
笔记:
使用 POINT 类时,存储坐标的参数顺序必须是 POINT(latitude, longitude)。
创建空间索引有一种特殊的语法。
使用 SDT 的最大好处是您可以访问空间分析函数,例如计算两点之间的距离 (ST_Distance) 并确定一个点是否包含在另一个区域内 (ST_Contains)。
CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
和有关 SDT 限制的警告,例如 James mentioned,也许您的答案会更简洁准确,以帮助其他人人也...
根据这篇 wiki 文章 http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy,MySQL 中的适当数据类型是 Decimal(9,6),用于将经度和纬度存储在单独的字段中。
使用 DECIMAL(8,6)
表示纬度(90 到 -90 度),使用 DECIMAL(9,6)
表示经度(180 到 -180 度)。 6 位小数适用于大多数应用程序。两者都应该“签名”以允许负值。
DECIMAL
类型用于不接受 floor/ceil
的财务计算。普通的 FLOAT
明显优于 DECIMAL
。
无需走太远,根据谷歌地图,lat 和 lng 最好是 FLOAT(10,6)。
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
mysql 8.0.17
开始,FLOAT
语法似乎已被弃用。 Mysql 现在建议只使用 FLOAT
而没有任何精度参数 dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html 和 dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
我们在 oracle 数据库中将纬度/经度 X 1,000,000 存储为 NUMBERS 以避免双精度数的舍入错误。
考虑到小数点后 6 位的纬度/经度精度为 10 厘米,这就是我们所需要的。许多其他数据库也将 lat/long 存储到小数点后 6 位。
在一个完全不同和更简单的角度来看:
如果您依靠 Google 来显示您的地图、标记、多边形等等,那么就让 Google 来完成计算吧!
您将资源保存在服务器上,只需将纬度和经度存储为单个字符串 (VARCHAR),例如:“-0000.0000001,-0000.000000000000001”(长度为 35,如果数字的十进制数超过 7 位,则四舍五入) ;
如果 Google 为每个数字返回超过 7 个十进制数字,那么无论如何您都可以将该数据存储在您的字符串中,以防您将来想检测一些逃跑或微生物;
您可以使用他们的距离矩阵或几何库来计算距离或检测某些区域中的点,调用如下所示:google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
您可以使用大量使用 Google Maps API 的“服务器端”API(在 Python、Ruby on Rails、PHP、CodeIgniter、Laravel、Yii、Zend 框架等中)。
这样,您就不必担心索引编号以及与可能破坏坐标的数据类型相关的所有其他问题。
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.2780818 和 X,21.2780819 之间有 1cm 的距离。因此,点后的 7 位数字为您提供 1/2 厘米的精度,而点后的 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 浮点类型 reference。它们中的任何一个都将像普通的 FLOAT 并且无论如何都等于 4 个字节。
现在空间通常不是问题,但是如果您出于某种原因想要真正优化存储(免责声明:不要进行预优化),您可以压缩 lat(不超过 91 000 个值 + 符号) + long(no超过 181 000 个值 + 符号)到 21 位,明显小于 2xFLOAT(8 字节 == 64 位)
虽然它不是所有操作的最佳选择,但如果您正在制作地图图块或使用只有一个投影的大量标记(点)(例如墨卡托,如谷歌地图和许多其他滑动地图框架所期望的),我发现了什么我称“大坐标系”非常非常方便。基本上,您以某种方式放大存储 x 和 y 像素坐标——我使用缩放级别 23。这有几个好处:
您对墨卡托像素进行一次昂贵的 lat/lng 转换,而不是每次处理该点时
从给定缩放级别的记录中获取平铺坐标需要右移一次。
从记录中获取像素坐标需要一次右移和一次按位与。
移位非常轻量级,可以在 SQL 中执行,这意味着您可以执行 DISTINCT 以每个像素位置仅返回一条记录,这将减少后端返回的记录数,这意味着更少的处理前端。
我在最近的一篇博文中谈到了这一切:http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
根据您的应用程序,我建议使用 FLOAT(9,6)
空间键将为您提供更多功能,但在生产基准测试中,浮点数比空间键快得多。 (平均 0,01 VS 0,001)
MySQL 对所有浮点数使用双精度...所以使用双精度类型。在大多数情况下,使用浮点数会导致不可预测的舍入值
DOUBLE
中执行操作。 MySQL 允许您将数据存储为 4 字节 FLOAT
或 8 字节 DOUBLE
。因此,将表达式存储到 FLOAT
列时可能会丢失精度。
纬度范围从 -90 到 +90(度),因此 DECIMAL(10, 8) 可以用于经度范围从 -180 到 +180(度),因此您需要 DECIMAL(11, 8)。
注意:第一个数字是存储的总位数,第二个是小数点后的数字。
简而言之:lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
我建议您对 SQL Server 使用 Float 数据类型。
存储 Lat Long 值的理想数据类型是 decimal(9,6)
这是大约 10 厘米的精度,同时仅使用 5 个字节的存储空间。
例如 CAST(123.456789 作为十进制 (9,6))
Lat Long 计算需要精度,因此请使用某种类型的小数类型并使精度至少比您将存储的数字高 2 以执行数学计算。我不知道我的 sql 数据类型,但在 SQL Server 中,人们经常使用浮点数或实数而不是十进制数并遇到麻烦,因为这些是估计数字而不是真实数字。所以只要确保你使用的数据类型是真正的十进制类型而不是浮点十进制类型,你应该没问题。
FLOAT
应该为您提供所需的所有精度,并且比将每个坐标存储为字符串等更适合比较函数。
如果您的 MySQL 版本早于 5.0.3,您可能需要注意某些 floating point comparison errors。
在 MySQL 5.0.3 之前,DECIMAL 列以精确的精度存储值,因为它们表示为字符串,但 DECIMAL 值的计算是使用浮点运算完成的。从 5.0.3 开始,MySQL 以 64 位十进制数字的精度执行 DECIMAL 操作,这应该解决涉及 DECIMAL 列时最常见的不准确问题
DECIMAL
由于使用浮动实现而(在 5.0.3 之前)存在某些错误。
DOUBLE
是 8 个字节。2 doubles == 16 bytes
)。