从给定点找到一定半径内的点的最有效方法

Most efficient way to find points within a certain radius from a given point

我已经在 SO 上阅读了关于这个主题的几个问题和答案,但我不明白哪种是找到 [=20 中所有点的常用方法(如果有的话......) =] 具有一定的半径,以给定的点为中心。

特别是我发现了两种最有说服力的方式:

select id, point 
from my_table 
where st_Distance(point, st_PointFromText('POINT(-116.768347 33.911404)', 4326)) < 10000;

和:

select id, point 
from my_table 
where st_Within(point, st_Buffer(st_PointFromText('POINT(-116.768347 33.911404)', 4326), 10000));

查询数据库的最有效方法是什么?还有其他选择要考虑吗?

创建缓冲区来查找点是一个明确的禁忌,因为 (1) 创建表示缓冲区的几何体的开销,以及 (2) 多边形中的点计算效率远低于一个简单的距离计算。

您显然正在处理(经度、纬度)数据,因此您应该将其转换为适当的笛卡尔坐标系,该坐标系与您的距离 10,000 具有相同的度量单位。如果该距离以米为单位,那么您还可以将点从 table 转换为 geography 并直接在(long, lat)坐标上计算。由于您只想识别指定距离内的点,因此可以在球体上使用 ST_DWithin() function 进行计算以提高速度(在非常高的纬度或非常长的距离时不要这样做):

SELECT id, point 
FROM my_table 
WHERE ST_DWithin(point::geography,
                 ST_GeogFromText('POINT(-116.768347 33.911404)'),
                 10000, false);

我使用了以下查询

SELECT *, ACOS(SIN(latitude) * SIN(Lat)) + COS(latitude) * COS(Lat) * COS(longitude) - (Long)) ) * 6380 AS distance FROM Table_tab WHERE ACOS( SIN(latitude) * SIN(Lat) + COS(latitude) * COS(Lat) * COS(longitude) - Long )) * 6380 < 10

上面查询的经纬度是数据库中的,lat,long是我们要搜索的点。

工作:它将计算数据库中所有点与搜索点之间的距离(以公里为单位),并检查距离是否小于 10 公里。它将return 10KM内的所有坐标。

我不知道 postgis 是如何做到最好的,但总的来说:

根据您的数据,可能最好先在正方形 边界框 中搜索(其中包含搜索区域圆圈)以消除大量候选对象,这应该非常快,因为您可以在 lon/lat 上使用简单的范围运算符,这些运算符理想地为此正确地建立了索引。 在使用半径的第二步搜索中。

此外,如果您的最高分数限制相对较低,并且您知道自己有很多候选人,您可以简单地先 'optimistic' 尝试在圈子内设置一个框,如果您找到足够的分数,完成!