首页 文章

在mysql中将纬度/经度存储为整数有什么缺点?

提问于
浏览
3

我有一个包含250.000.000行的大型MySQL表,其中存储了不同类型的点和坐标 . 该表包含以下列:

NodeId Lat Lon

到目前为止,Lat和Lon字段是FLOAT(10,7)类型,但我正在尝试将它们更改为INT,因为查询此表可能非常慢,即使我已将两个Lat / Lon列索引在一起,并且Lon专栏本身 .

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

我想将两列更改为Integer的原因是因为我将按Lat分区表格,并将其索引为Lon,以使搜索更快 .

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

1.这种方法会使我的边界框查询更快吗? 2.将纬度和经度坐标存储为整数值是否有任何缺点?

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

2 回答

  • 1

    您不可能从这两者中获得搜索性能提升

    • 分区表或

    • 将lat / lon的数据类型从FLOAT更改为INTEGER .

    为什么不?

    • FLOAT和INTEGER:32位存储的数据量相同 .

    • FLOAT为GPS分辨率数据提供了足够的精度 . 如果您了解并关心UTM和Lambert投影之间的差异,请使用DOUBLE .

    • 索引范围搜索适用于FLOAT,DOUBLE和INTEGER .

    • 如果对表进行分区,则需要做额外的工作以保持索引范围搜索不会碰到很多分区 . 点击大量分区会使搜索速度变慢 .

    如果你在特定的纬度/经度边界框中寻找点,那么在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 列上的直接范围扫描 . 如果是's indexed that is fast even if it' s FLOAT 数据类型 . (latitude, longitude) 上的复合索引应该非常好,特别是如果你可以保持你的搜索半径相当小 .

    现在,有一个复杂的问题 . 有25亿分,您的查询可能就是这样做的 .

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

    在这种情况下,您需要 (point_type, latitude, longitude) 上的复合索引,因此查询可以做正确的事情 . 使用大小的表,您确实需要了解您的查询以使您的索引正确 .

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

  • 1

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

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

相关问题