请记住,我将在lat / long对上执行计算,哪种数据类型最适合与MySQL数据库一起使用?
使用MySQL的spatial extensions和GIS。
我们在oracle数据库中将纬度/经度X 1,000,000存储为NUMBERS,以避免双打出现错误。
鉴于小数点后第6位的纬度/经度是10厘米精度,这就是我们所需要的。许多其他数据库也将lat / long存储到第6个小数位。
从一个完全不同和更简单的角度来看:
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类型。在大多数情况下,使用float会导致不可预测的舍入值
虽然它并非对所有操作都是最佳的,但如果您正在制作地图图块或使用大量标记(点)只使用一个投影(例如墨卡托,如谷歌地图和许多其他滑动地图框架预期),我找到了什么我称之为“Vast Coordinate System”非常非常方便。基本上,你以某种方式存储x和y像素坐标 - 放大 - 我使用缩放级别23.这有几个好处:
我在最近的博客文章中谈到了这一切:http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
我对一些答案/评论感到非常惊讶。
为什么有人愿意自愿“预先降低”精度,然后再对更糟糕的数字进行计算呢?听起来最愚蠢。
如果源具有64位精度,那么自愿将比例缩小到例如是愚蠢的。 6位小数,并将精度限制为最多9个重要的数字(通常建议的十进制9.6格式)。
当然,可以使用源材料具有的精度来存储数据。降低精度的唯一原因是存储空间有限。
十进制9.6格式导致对齐网格现象。这应该是最后一步,如果它完全发生的话。
我不会邀请积累的错误到我的巢。
PostGIS中的空间函数比MySQL空间函数中的空间函数功能更强大(即不受BBOX操作限制)。看看:link text
TL; DR
如果你不是在NASA /军队工作而不是制造飞机导航系统,请使用FLOAT(8,5)。
要完全回答您的问题,您需要考虑以下几点:
格式
所以答案的第一部分是 - 您可以以应用程序使用的格式存储坐标,以避免来回不断的转换并进行更简单的SQL查询。
很可能您使用谷歌地图或OSM来显示您的数据,而GMaps使用“十进制度数2”格式。因此,以相同的格式存储坐标会更容易。
精确
然后,您想要定义所需的精度。当然你可以存储像“-32.608697550570334,21.278081997935146”这样的坐标,但你有没有关心导航到点的毫米?如果你不是在美国国家航空航天局工作而不是做卫星或火箭或飞机轨迹,那么你应该没有几米精度。
常用格式是点后5位数,精度为50cm。
示例:X,21.2780818和X之间的距离为1厘米,21.2780819。因此,点后7位数字给你1 / 2cm精度,点后5位数将给你1/2米精度(因为不同点之间的最小距离是1米,因此舍入误差不能超过它的一半)。对于大多数民用目的来说应该足够了。
度十进制分钟格式(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类型reference。它们中的任何一个都将像普通的FLOAT一样,无论如何都等于4个字节。
通常空间现在不是问题,但如果你想出于某种原因真的优化存储(免责声明:不做预优化),你可以压缩lat(不超过91 000值+符号)+ long(no超过181 000个值+符号)到21位,明显小于2xFLOAT(8个字节== 64位)
注意:第一个数字是存储的总位数,第二个数字是小数点后面的数字。
简而言之:lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Lat Long计算需要精度,因此请使用某种类型的十进制类型,并使精度至少比存储的数字高2,以便执行数学计算。我不知道我的sql数据类型,但在SQL服务器中,人们经常使用float或real而不是decimal,并且遇到麻烦,因为这些是估计的数字而不是真正的数字。因此,只需确保您使用的数据类型是真正的十进制类型而不是浮动十进制类型,您应该没问题。
谷歌为使用谷歌地图的“商店定位器”应用程序提供了一个开始完成PHP / MySQL解决方案。在此示例中,它们将lat / lng值存储为“Float”,长度为“10,6”
FLOAT
应该为您提供所需的所有精度,并且比将每个坐标存储为字符串等更好地用于比较功能。
如果你的MySQL版本早于5.0.3,你可能需要注意某些floating point comparison errors。
在MySQL 5.0.3之前,DECIMAL列以精确的精度存储值,因为它们表示为字符串,但DECIMAL值的计算是使用浮点运算完成的。从5.0.3开始,MySQL执行DECIMAL操作,精度为64位十进制数,这可以解决DECIMAL列中最常见的不准确问题
基本上,它取决于您所在位置所需的精度。使用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
希望这可以帮助。
MySQL的Spatial Extensions是最佳选择,因为您可以使用空间运算符和索引的完整列表。空间索引将允许您非常快速地执行基于距离的计算。请记住,从6.0开始,Spatial Extension仍然不完整。我没有放下MySQL Spatial,只是在你对这个问题做出太多分析之前让你知道陷阱。
如果您严格处理积分并且只处理DISTANCE功能,那么这很好。如果需要使用“多边形”,“线”或“缓冲点”进行任何计算,则除非使用“关联”运算符,否则空间运算符不会提供精确结果。请参阅21.5.6顶部的警告。诸如包含,内部或相交之类的关系使用MBR,而不是精确的几何形状(即,椭圆被视为矩形)。
此外,MySQL Spatial中的距离与第一个几何体的距离相同。这意味着如果您使用十进制度数,则您的距离测量值为十进制度数。这将使你很难得到准确的结果,因为你从赤道得到了更好的结果。
当我为ARINC424构建的导航数据库执行此操作时,我进行了大量测试并回顾了代码,我使用了DECIMAL(18,12)(实际上是NUMERIC(18,12)因为它是firebird)。
浮点数和双打数据并不精确,可能会导致舍入错误,这可能是一件非常糟糕的事情。我不记得我是否发现任何有问题的真实数据 - 但我相当确定无法准确存储在浮点数或双数据中可能会导致问题
关键是当使用度数或弧度时,我们知道值的范围 - 并且小数部分需要最多的数字。
MySQL Spatial Extensions是一个很好的选择,因为他们遵循The OpenGIS Geometry Model。我没有使用它们,因为我需要保持数据库的可移植性。
取决于您需要的精度。
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)
。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位。两者都应该“签名”以允许负值。
根据谷歌地图,没有必要走远,最好的是lat和lng的FLOAT(10,6)。