给定纬度/经度的基于距离的 JOIN

Posted

技术标签:

【中文标题】给定纬度/经度的基于距离的 JOIN【英文标题】:Distance-based JOIN given Latitude/Longitude 【发布时间】:2012-02-15 09:46:38 【问题描述】:

给定以下表格:

table A (id, latitude, longitude)
table B (id, latitude, longitude)

如何构建一个高效的 T-SQL 查询,将 A 中的每一行与 B 中最近的行相关联?

ResultSet 应该包含 A 中的所有行,并将它们与 B 中的 1 个且只有 1 个元素相关联。我正在寻找的格式如下:

(A.id, B.id, distanceAB)

我有一个函数可以计算给定 2 对纬度和经度的距离。我使用order by ... limit 1 和/或rank() over (partition by ...) as rowCount ... where rowCount = 1 尝试了一些东西,但结果要么不是我真正需要的,要么需要很长时间才能返回。

我错过了什么吗?

【问题讨论】:

【参考方案1】:

没有办法绕过这样一个事实,即您必须将 A 中的每条记录与 B 中的每条记录进行比较,如果 A 和 B 都包含大量记录,那么显然扩展性会很差。

话虽如此,这将返回正确的结果:

SELECT aid, bid, distanceAB
FROM (
  SELECT aid, bid, distanceAB,
    dense_rank() over (partition by aid order by distanceAB) as n
  FROM (
    SELECT a.id as aid, B.id as bid,
      acos(sin(radians(A.lat)) * sin(radians(B.lat)) +
        cos(radians(A.lat)) * cos(radians(B.lat)) *
        cos(radians(A.lon - B.lon))) * 6372.8 as distanceAB
    FROM A cross join B
  ) C
) D
WHERE n = 1

如果您的集合不是太大,这将在合理的时间内返回。 A 有 3 个位置,B 有 130,000 个左右,在我的机器上大约需要一秒钟。每条记录 1,000 条记录大约需要 40 秒。就像我说的,它的扩展性很差。

需要注意的是,Sparky 的回答在某些情况下可能会返回不正确的结果。假设您的 A 位置在 +40,+100。 +40,+111 不会返回,即使它比 +49,+109 更接近。

【讨论】:

【参考方案2】:

这是一种性能应该不错的方法,但需要注意的是它可能找不到任何结果

    select top 1 a.id,b.id,dbo.yourFunction() as DistanceAB
    from a 
    join b on b.latitude between a.latitude-10 and a.latitude+10 and
              b.longititude between a.longitude-10 and b.longittude+10
    order by 3

您所做的基本上是在 A 的大约 20 个单位半径内寻找任何 B 行,然后按您的函数对其进行排序以确定最接近的。您可以根据需要调整单位半径。虽然它并不准确,但它应该会减少结果集的大小,并且应该会给您带来不错的性能结果。

【讨论】:

【参考方案3】:

连接两个子查询是可能的。第一个包含 A 和 B 位置之间的所有距离,第二个仅包含 B 位置与 A 位置的最小距离。

SELECT x.aid, x.bid, x.distance
FROM
(SELECT A.ID AS aid, 
        B.ID AS bid, 
        SQRT(A.Latitude * A.Latitude + B.Longitude * B.Longitude) AS Distance
     FROM LocationsA AS A 
     CROSS JOIN LocationsB AS B) x JOIN
(SELECT A.ID AS aid, 
        MIN(SQRT(A.Latitude * A.Latitude + B.Longitude * B.Longitude)) AS Distance
     FROM LocationsA AS A 
     CROSS JOIN LocationsB AS B
     GROUP BY A.ID) y ON x.aid = y.aid AND x.Distance = y.Distance

【讨论】:

以上是关于给定纬度/经度的基于距离的 JOIN的主要内容,如果未能解决你的问题,请参考以下文章

给定(纬度,经度)点,距离和方位,如何获得新的经纬度

获取给定当前点、距离和方位的纬度/经度

计算给定2点,纬度和经度的距离[重复]

使用经度和纬度查找给定距离内的所有附近客户

给定初始纬度 lng,距离和方位角,在 php 中查找纬度经度点

在给定特定纬度/经度的情况下,如何计算与纽约附近地铁入口的距离?