请记住,我将在经纬度对上执行计算,哪种数据类型最适合与MySQL数据库一起使用?
请记住,我将在经纬度对上执行计算,哪种数据类型最适合与MySQL数据库一起使用?
Answers:
在GIS中使用MySQL的空间扩展。
Google为使用Google Maps的示例“ Store Locator”应用程序提供了一个完成PHP / MySQL解决方案的起点。在此示例中,他们将经度/经度值存储为“浮点数”,长度为“ 10,6”
FLOAT(10,6)
在坐标的整数部分保留4位数字。不,符号不计数-来自(un)signed属性。
Double
为Laravel 使用数据类型
基本上,这取决于您所需的位置精度。使用DOUBLE,您将拥有3.5nm的精度。DECIMAL(8,6)/(9,6)下降到16cm。浮标为170万...
这个非常有趣的表具有更完整的列表: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是最佳选择,因为您可以使用完整的空间运算符和索引列表。空间索引使您可以非常快速地执行基于距离的计算。请记住,从6.0版开始,空间扩展仍不完整。我并没有放弃MySQL Spatial,只是让您知道了陷阱,然后再进行深入的探讨。
如果您只处理点,而仅处理DISTANCE函数,那很好。如果需要使用多边形,直线或缓冲点进行任何计算,除非您使用“关系”运算符,否则空间运算符不会提供确切的结果。请参阅21.5.6顶部的警告。诸如包含,内部或相交之类的关系使用的是MBR,而不是确切的几何形状(即,椭圆被视为矩形)。
另外,MySQL Spatial中的距离与第一个几何图形的单位相同。这意味着,如果您使用的是小数度,则距离的测量单位为小数度。当您从赤道上走远时,这将很难获得准确的结果。
当我对使用ARINC424构建的导航数据库进行此操作时,我进行了大量测试并回顾了代码,我使用了DECIMAL(18,12)(实际上是NUMERIC(18,12),因为它是火鸟)。
浮点数和双精度数不够精确,可能会导致舍入错误,这可能是非常糟糕的事情。我不记得我是否发现任何有问题的真实数据-但我很确定不能正确存储浮点数或双精度数会导致问题
关键是,使用度或弧度时,我们知道值的范围-小数部分需要最多的数字。
在MySQL中的空间扩展是一个很好的选择,因为他们遵循的开放GIS几何模型。我之所以没有使用它们,是因为我需要保持数据库的可移植性。
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开始,请考虑使用空间数据类型(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位是可以的。两者都应进行“签名”以允许使用负值。
DECIMAL
类型用于不floor/ceil
接受的财务计算。普通FLOAT
股明显优于大市DECIMAL
。
根据Google Maps的说法,无需走太远,最好的纬度和经度是FLOAT(10,6)。
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
不赞成使用该语法mysql 8.0.17
。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,以避免四舍五入的错误。
假设到小数点后第六位的经度/纬度为10厘米,这是我们所需要的。许多其他数据库也存储纬度/经度到小数点后第六位。
从完全不同和更简单的角度来看:
VARCHAR
),例如:“ -0000.0000001,-0000.000000000000001 ”(长度为35,如果一个数字的位数超过7个,则四舍五入)。google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
这样,您就不必担心索引编号以及与数据类型相关联的所有其他问题,这些问题可能会破坏您的坐标。
根据您的应用程序,我建议使用FLOAT(9,6)
空间键将为您提供更多功能,但是按生产基准测试,浮标比空间键快得多。(AVG中的0,01 VS 0,001)
MySQL对所有浮点数都使用double。因此,请使用double类型。在大多数情况下,使用浮点数将导致不可预测的舍入值
DOUBLE
。MySQL使您可以将数据存储为4字节FLOAT
或8字节DOUBLE
。因此,将表达式存储到FLOAT
列中时可能会失去精度。
虽然并非所有操作都最佳,但是如果您仅使用一个投影就制作地图图块或使用大量标记(点)(例如Mercator,例如Google Maps和许多其他滑动地图框架所期望的),我发现了什么我称“大型坐标系”非常方便。基本上,您以某种方式存储x和y像素坐标-我使用的是缩放级别23。这有几个好处:
我在最近的博客文章中谈到了所有这些问题:http : //blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
我对某些答案/评论感到非常惊讶。
到底为什么有人愿意自愿“降低”精度,然后在以后对更差的数字进行计算呢?听起来最终是愚蠢的。
如果源具有64位精度,则自愿将比例固定为例如,这肯定是愚蠢的。6位小数,并将精度限制为最多9位有效位数(通常建议的9.6位十进制格式会发生这种情况)。
自然地,人们以原始资料所具有的精度来存储数据。降低精度的唯一原因将是有限的存储空间。
十进制9.6格式会导致捕捉到网格现象。如果这真的发生的话,那应该是最后一步。
我不会邀请累积的错误来我的巢。
TL; DR
如果您不是在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,说谷歌建议将它存储在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位)
我建议您对SQL Server使用Float数据类型。
Lat Long计算需要精度,因此请使用某种类型的十进制类型,并使精度至少比要存储的数字高2以便执行数学计算。我不知道我的sql数据类型,但是在SQL Server中,人们经常使用float或real而不是小数,并且遇到麻烦,因为这些是估计数字,不是真实数字。因此,只需确保使用的数据类型是真正的十进制类型,而不是浮点十进制类型,就可以了。
A FLOAT
应该为您提供所需的所有精度,并且比起将每个坐标存储为字符串等,它对于比较函数而言要更好。
如果您的MySQL版本低于5.0.3,则可能需要注意某些浮点比较错误。
在MySQL 5.0.3之前,DECIMAL列以精确的精度存储值,因为它们以字符串表示,但是DECIMAL值的计算是使用浮点运算完成的。从5.0.3开始,MySQL以64位十进制数字的精度执行DECIMAL操作,这应该可以解决DECIMAL列中最常见的不准确问题。
DECIMAL
由于使用浮动实现,在5.0.3之前存在某些错误。