1

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

2如果地相同,则它们是相同的:

  • 姓名
  • 纬度
  • 经度

因此,服务器尝试通过发出来识别提交的地标是否已经存在

SELECT id FROM Placemark WHERE name=x, latitude=y, longitude=x

  • 在 iOS 中,latitudelongitude度数和类型CLLocationDegrees为单位报告<CoreLocation>
  • 在 MySQL 中,latitude定义longitudeDOUBLE


问题:
存储坐标时精度丢失,例如:
latidudeof 50.09529561485427is stored as 50.0952956148543
longitudeof -122.9893130423316is stored as-122.989313042332

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

笔记:

  • 我不能将坐标存储为TEXTorVARCHAR因为我需要能够说SELECT placemarks coordinates BETWEEN x AND y或执行其他算术选择
  • 我不能使用 MySQL 的空间扩展,因为可移植性是一个问题,而且据我了解,空间数据类型在用作键时非常慢(而且我的用例需要通过坐标选择)

任何帮助表示赞赏

4

2 回答 2

3

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

This has the following interesting consequence: The precision seems to be lost in an identical manner even when I bind keys to my subsequent search queries, and therefore almost "accidentally" the correct result is returned. That is, the key (coordinates) is stored incorrectly, and then subsequent selects also convert query keys incorrectly, but in a matching manner, and therefore the record is found. Given that the conversions due to precision loss are always performed on the same platform (the server), it's probably safe to leave as is?? Or maybe not, perhaps a future migration exercise (i.e., due to scaling) will make the rounding errors apparent.

Yawar's pointer led me to MySQL's manual which explains that floating point numbers can be stored without loss of precision as DECIMAL:

"Exact-value numeric literals have an integer part or fractional part, or both. They may be signed" http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.html

Given that the existing solution seems to work, the question then becomes, is it better to keep the DB data type DOUBLE, or switch to DECIMAL?

Storage:
Latitude has range from -90 to +90, and iOS seems to use precision of 14 decimals
Longitude has range from -180 to +180, which leaves precision of 13 decimals on iOS

That means we need:
Latitude : DECIMAL(16,14), which takes less the 8 bytes of storage (4 bytes for each pack of 9d)
Longitude: DECIMAL(16,13), also requiring less than 8 bytes of storage

In contrast, a column of type DOUBLE requires 8 bytes of storage.

Speed (arithmetic):
Floating point arithmetic will almost always be materially faster because it is supported natively by the hardware

Speed (searches):
I believe index of DECIMAL vs index of DOUBLE have a very comparable runtime.

Conclusion:
Switching to DECIMAL eliminates the precision errors and also reduces storage requirements, at an arithmetic performance penalty which is negligible in this use case.

于 2013-02-19T06:08:48.800 回答
0

Instead of storing latitude and longitude as double, multiply by 1000000, convert to integer, and store that. Of course, divide by 1000000.0 if you need to read them back in your app.

This will give you plenty of accuracy (0.000001º) for placemarks and will eliminate floating point conversion and precision problems that you are having and take up slightly less space. I use this in my own data (it's binary, not SQL) and call them MicroDegrees.

于 2013-02-21T05:26:15.970 回答