在 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。
您不太可能通过这两种方式实现搜索性能提升
- 分区 table 或
- 正在将 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.
我有一个很大的 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。
您不太可能通过这两种方式实现搜索性能提升
- 分区 table 或
- 正在将 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.