在MySQL中存储CLLocationDegrees时丢失精度

在MySQL中存储CLLocationDegrees时丢失精度,mysql,ios,double,core-location,precision,Mysql,Ios,Double,Core Location,Precision,我正在开发一个小应用程序,将iOS设备指定的位置标记存储到MySQL后端。当一个设备保存一个新的Placemark时,它被插入到数据库中,新生成的ID被发送回客户端。如果另一个设备试图保存同一个Placemark,服务器需要确定它已经存在于数据库中,而不是插入和生成新的ID,它需要将该Placemark的现有ID发送回客户端 如果两个位置标记相同,则它们是相同的: 名字 纬度 经度 因此,服务器试图通过发出 从Placemark中选择id,其中名称=x,纬度=y,经度=x 在iOS中,纬度

我正在开发一个小应用程序,将iOS设备指定的位置标记存储到MySQL后端。当一个设备保存一个新的Placemark时,它被插入到数据库中,新生成的ID被发送回客户端。如果另一个设备试图保存同一个Placemark,服务器需要确定它已经存在于数据库中,而不是插入和生成新的ID,它需要将该Placemark的现有ID发送回客户端

如果两个位置标记相同,则它们是相同的:

  • 名字
  • 纬度
  • 经度
因此,服务器试图通过发出

从Placemark中选择id,其中名称=x,纬度=y,经度=x

  • 在iOS中,
    纬度
    经度
    以度为单位,类型为
    CLLocationDegrees
    ,如
  • 在MySQL中,
    latitude
    longitude
    被定义为
    DOUBLE

问题:
存储坐标时会丢失精度,例如:
50.09529561485427的
latidude
存储为
50.0952956148543

-122.9893130423316
经度
存储为
-122.989313042332

问题:
我可以在MySQL中使用不同的数据类型,以便完整地存储每个坐标吗

注意事项:

  • 我无法将坐标存储为
    TEXT
    VARCHAR
    ,因为我需要能够说
    选择x和y之间的坐标,或者执行其他算术选择
  • 我不能使用MySQL的空间扩展,因为可移植性是一个问题,而且据我所知,空间数据类型用作键时速度非常慢(我的用例要求按坐标选择)

实际上,进一步的测试揭示了以下奇怪的结果:当DB驱动程序将数据绑定到查询语句时,以及在数据实际插入DB之前,精度会丢失

这有以下有趣的结果:即使在我将键绑定到后续搜索查询时,精度似乎以相同的方式丢失,因此几乎“意外”返回了正确的结果。也就是说,键(坐标)存储不正确,随后的选择也会以匹配方式错误地转换查询键,因此会找到记录。由于精度损失导致的转换总是在同一平台(服务器)上执行,所以保持原样可能是安全的??也许不是,也许未来的迁移练习(即,由于缩放)会使舍入误差变得明显

Yawar的指针将我引向MySQL的手册,其中解释了浮点数可以在不损失精度的情况下存储为十进制:

精确值数字文字有整数部分或小数部分,或两者都有。它们可能是有符号的

考虑到现有的解决方案似乎有效,那么问题就变成了,是保留DB数据类型
DOUBLE
,还是切换到
DECIMAL

存储:
纬度
的范围从
-90到+90
,而iOS似乎使用了
14位小数的精度

经度
的范围为
-180到+180
,这使得iOS上的精度为
13位小数

这意味着我们需要:
Latitude
DECIMAL(16,14)
,它占用的存储空间少于8字节(每包9d存储4字节)
经度
十进制(16,13)
,也需要少于8字节的存储空间

相反,
DOUBLE
类型的列需要8字节的存储空间

速度(算术):
浮点运算几乎总是实质性地更快,因为硬件本身就支持它

速度(搜索):
我相信
DECIMAL
索引与
DOUBLE
索引的运行时间非常相似

结论:

切换到
DECIMAL
可以消除精度错误,还可以减少存储需求,在这种情况下,算术性能损失可以忽略不计。

而不是将纬度和经度存储为double,乘以1000000,转换为整数,然后存储。当然,如果您需要在应用程序中重新读取它们,则除以1000000.0


这将为您提供足够的精度(0.000001º),并消除浮点转换和精度问题,占用的空间稍小。我在自己的数据(是二进制的,不是SQL)中使用它,并称之为微度数。

除了你的问题,在谷歌地图中输入两个坐标会给我一个几乎相同的位置(相差几英尺)。你真的需要那么高的精确度吗?嗨,DTs。我建议把这个问题作为一个重复的问题来结束——你可以很容易地将这个答案应用到你的CLLocationDegrees问题上。请记住,我在WHERE子句中使用这些坐标。它们需要保持完整,不是因为我需要超精确地识别一个Placemark,而是因为它们在后续搜索中被用作键。@DTs浮点数据对于任何类型的键值都不是很好的选择-如果两个浮点值相同,甚至几乎不可能精确比较。你必须和epsilon比较。我会重新考虑你的程序架构,如果它依赖于保持精确值的浮点值如果它没有用作键,只是一个范围内的值,则scotts建议是有效的。