在 mysql 中将 latitude/longitude 存储为整数有什么缺点?

What is the drawback of storing latitude/longitude as integer in mysql?

我有一个很大的 MySQL table 包含 +250.000.000 行,我在其中存储不同类型的点和坐标。 table 包含以下列:

NodeId      Lat      Lon

到目前为止,Lat 和 Lon 字段都是 FLOAT(10,7) 类型,但我正在尝试将它们更改为 INT,因为查询此 table 可能非常慢,即使我已经将 Lat/Lon 列一起编入索引,并单独编入 Lon 列。

如果我没记错的话,MySQL在搜索时只使用一个索引。

我想将两列更改为 Integer 的原因是,例如我会按 Lat 对 table 进行分区,并按 Lon 对其进行索引,以加快搜索速度。

基本上,我有两个问题正在寻找答案:

1. Would this kind of approach make my bounding box queries faster?

2. Are there any drawbacks of storing Latitude and Longitude coordinates as Integer values?

编辑:我没有提到的是原始 FLOAT 值在存储为整数之前乘以 10.000.000。

您不太可能通过这两种方式实现搜索性能提升

  1. 分区 table 或
  2. 正在将 lat/lon 的数据类型从 FLOAT 更改为 INTEGER。

为什么不呢?

  • 存储的数据量对于 FLOAT 和 INTEGER 是相同的:32 位。
  • FLOAT 为 GPS 分辨率数据提供了足够的精度。如果您知道并关心 UTM 和 Lambert 投影之间的差异,请使用 DOUBLE。
  • 对于 FLOAT、DOUBLE 和 INTEGER,索引范围搜索工作正常。
  • 如果您对 table 进行分区,您将需要做额外的工作来防止索引范围搜索命中很多分区。命中大量分区会使搜索变慢。

如果您正在寻找特定 lat/lon 边界框内的点,在 MySQL:

中看起来会像这样
SET @radius := 50;  /* 50km */
SET @units := 111.045l  /* kilometers per degree */
SET @lat := 40.7484;
SET @lon := ,-73.9857;

SELECT ...
 WHERE table.latitude 
  BETWEEN @lat  - (@radius / @units )
      AND @lat  + (@radius / @units )
  AND table.longitue
  BETWEEN @lon - (@radius / @units * COS(RADIANS(@lat))))
      AND @lon + (@radius / @units * COS(RADIANS(@lat)))) 

请注意,这采用的形式是

     table.latitude  BETWEEN constant AND constant
 AND table.longitude BETWEEN constant AND constant

这两项中的第一项是对 latitude 列的直接范围扫描。如果它被索引,即使它是 FLOAT 数据类型也很快。 (latitude, longitude) 上的复合索引应该很不错,特别是如果您可以将搜索半径保持在相当小的范围内。

现在,有一个并发症。有了 2.5 亿点,您的查询可能正在执行类似的操作。

     table.point_type = constant
 AND table.latitude  BETWEEN constant AND constant
 AND table.longitude BETWEEN constant AND constant

在那种情况下,您需要 (point_type, latitude, longitude) 上的复合索引,以便查询可以做正确的事情。对于 table 这样的大小,您确实需要了解您的查询才能使索引正确。

最后,根据您拥有的点数,您可以考虑使用 MySQL 的地理空间扩展进行位置搜索。这是写在这里。 http://www.plumislandmedia.net/mysql/using-mysqls-geospatial-extension-location-finder/ 但是当其元素之一是地理空间时,您不能创建复合索引。

这将 运行 绕过所有其他技术。但是,它需要一些准备工作: http://mysql.rjweb.org/doc.php/latlng

正如该博客指出的那样,乘以 10000 并存储在 MEDIUMINT 中将为您节省 500MB。分辨率为 16 米/52 英尺。如果您需要更严格的分辨率,则建议使用 INT 解决方案(16 毫米/<1 英寸)。 FLOAT,没有不必要的 (10,7) 给你 1.7m / 5.6ft.