【问题标题】:Max latitude for x distance from longitude - Max longitude for x distance from latitude - SQL与经度的 x 距离的最大纬度 - 与纬度的 x 距离的最大经度 - SQL
【发布时间】:2016-08-29 07:45:38
【问题描述】:

现在我有一个包含 1 亿次插入的表:

CREATE TABLE o (
    id          int UNIQUE,
    latitude    FLOAT(10, 8),
    longitude   FLOAT(11, 8)

);

在我的后端,我收到一个用户 lat/long 并尝试返回 x 距离内的所有内容。

我认为我可以计算 X 距离的最大纬度/经度,而不是对每个结果都进行距离公式。

所以我们通过找到最大纬度/最小纬度、最大经度/最小长度来创建一个正方形。

一旦我们有了这些最大值,我们就会对这个值范围进行查询,从而使我们的子集显着减小,然后再执行实际距离公式(即,找到 X 距离内的值)。

所以我的问题是: 是什么让我跑得更快?

选项 1)

  • 1亿条目的距离公式得到集合。

选项 2)

  • 我们计算的是最小/最大纬度/经度,而不是对 1 亿个条目的集合执行距离公式。
  • 从一亿个条目的表中选择该范围内的值
  • 在我们新的较小集合上计算距离公式。

选项 3)

  • SQL 中已经存在这方面的内容

如果选项 2 更快,那么下一个问题实际上是解决该数学问题。

如果你想看那个继续阅读:

经/长距离公式

dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2(sqrt(a), sqrt(1-a)) 
d = R * c

显然我们可以重新排列,因为 D(假设 1 英里)和 R(是地球的半径)是一个设定值,所以我们得到 D/R = C。

那么问题来了,我们如何计算 C/2 = atan2(sqrt(a), sqrt(1-a))?

【问题讨论】:

  • 你在重新发明轮子。看mysql空间数据类型和函数。

标签: mysql math latitude-longitude


【解决方案1】:

1 -- 100M 行需要扫描和测试很多。偶尔做一次没关系,但是做很多太慢了。

2 -- 使用伪方形边界框并做

WHERE latitude  BETWEEN ...
  AND longitude BETWEEN ...

是很好的第一步。纬度范围是一个简单的常数乘以 X;经度范围也除以cos(latitude)

但是,当您尝试仅在正方形中找到这些行时,问题就来了。 latitude 和/或 longitude 上的任何索引组合,无论是单独还是一起,都只会部分过滤。也就是说,它将忽略经度并为您提供纬度范围内的所有内容,反之亦然。这可能会让你减少到 100,000 行来检查距离。这比 100,000,000 好多了,但没有你希望的那么好。

3 -- http://mysql.rjweb.org/doc.php/latlng 确实到了广场,或者很近。它旨在扩展。我只测试了 3M 行,而不是 100M,但它应该可以正常工作。

主要技巧是在纬度上进行分区,然后将经度作为PRIMARY KEY 中的第一列,以便 InnoDB 将附近的行聚集在分区中。如果您查找 X 英里(或公里)内的所有行,它可能会查看(并计算大圆距离)大约两倍的行,而不是 100K。如果你想找到最近的 100 个项目,它可能会触及大约 400 (4x)。

至于SPATIAL 索引,您可能想要升级到5.7.6,这是在添加ST_Distance_Sphere()ST_MakeEnvelope() 的时候。 (MakeEnvelope 只比自己构建多边形方便一点——它有扁平地球综合症。)

【讨论】:

    猜你喜欢
    • 2020-11-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    相关资源
    最近更新 更多