如何在Oracle中高效地计算坐标之间的距离

时间:2009-10-19 21:45:15

标签: oracle gps geo

我有一个大型Oracle数据库(720,000条记录aprox),其中每条记录都有自己的地理坐标(lat& lng),我只需要选择距离某一点特定距离的记录(在特定半径范围内) )。

目前我已经在oracle论坛中实现了一个距离函数(基于hasrsine),但由于数据库有点大,每次选择花费大约50秒。

有关如何有效地进行任何建议吗?我知道有一个名为oracle spatial& amp;定位器,但我不知道我是否可以购买它甚至它是如何工作的。非常感谢提前。最好的问候

8 个答案:

答案 0 :(得分:5)

使用更好的算法。不需要计算需要平方根计算的实际欧几里德距离,而是选择仅需要减法和加法的线性距离。即如果您的点位于(10,10)并且您的半径为5,则选择由(10 +/- 5,10 +/- 5)形成的正方形内的点的所有位置。

这将在广场的角落捕获少量误报。通过计算适当的欧几里德距离,仔细检查应用程序中的结果来消除这些。

答案 1 :(得分:5)

提供有关Lat和Long值的特定格式的更多详细信息,以及用于实现hasrsine的特定公式。

有三种方法可以加快速度。根据具体情况,我们至少可以做到其中两种。

  1. 通过简单的属性值比较尽可能多地删除记录。

    对于这些记录,我们根本不需要计算任何东西 例如,将最大半径要求转换为符合条件的经度(可能是纬度)的[慷慨但近似]范围

  2. 使用替代(可能是近似的)距离测量 例如,基于向上舍入的坐标计算eucldidian距离的平方可能更快。 (当然要将其与所需半径的平方进行比较)

  3. 改善实施半胱氨酸配方的方式

答案 2 :(得分:4)

一些建议,如果你还没有这样做......

  1. 由于Haversine计算需要以弧度表示的角度,如果要以度为单位存储纬度和经度,请添加几列并预先计算弧度等值。更一般地,预先计算函数中可用于公式的任何值并存储它们。

  2. 考虑使用更简单的函数来消除远在半径之外的点,仅在基于更简单函数的潜在匹配的那些上运行Haversine函数。对于度数,您可以使用SQRT((69.1 * dLat) 2 +(53 * dLong) 2 ))并使用一些软糖因子(10%)。如果您需要比简单计算所提供的更好,则仅在与粗糙近似匹配的点上运行您的Haversine计算。

答案 3 :(得分:3)

如果您拥有许可证,则可以使用Oracle Spatial

Oracle Docs - Oracle Spatial

我没有使用它,但快速扫描文档会指向函数SDO_WITHIN_DISTANCE

答案 4 :(得分:2)

“特定距离”是否有些不变? IE总是在寻找“1英里内的所有点”或半径是否会发生变化?

您希望在任何给定查询中返回的总记录的百分比是多少? 10%? 0.10%?

如果您将始终具有相同的半径,请构建一个与半径长度相同的正方形网格。为每个分配相邻方块列表。每个点都知道它所在的方格,从中可以得到所有相邻方格的列表。然后仅对这些方块中的点运行计算。这类似于弹出的其他答案,但会更快,因为线性计算在索引查找中近似,而不是在每个点之间计算。

即使使用可变半径,您仍然可以使用上述内容,但您必须计算要包含的“邻居”数量。只有当您希望从任何单个查询中获得总数的一小部分时,这些才可行。

答案 5 :(得分:1)

如果您不需要距离太准确,您可以将地球视为平坦。来自this discussion

  

以英里为单位的近似距离:

sqrt(x * x + y * y)
     

其中x = 69.1 *(lat2 - lat1)且y =   53.0 *(lon2 - lon1)

我最近对mysql进行了一些优化(在此处概述:www.mooreds.com/wordpress/archives/000547 [对不起,每个帖子我只获得1个超链接])但我不确定我经历了多少步骤适用于Oracle。一些肯定是(如果可能的话,使用边界框)。

答案 6 :(得分:0)

Approximate distance in miles:

sqrt(x * x + y * y) 
where x = 69.1 * (lat2 - lat1) and y = 53.0 * (lon2 - lon1)

你可以获得更准确的结果......如果你改变了53.0幻数......也要考虑到纬度的变化。 (当你走向两极时,逐渐变小。)

有没有人有魔术般的魔法公式?

答案 7 :(得分:0)

首先,Haversine并不完美,因为地球不是一个完美的领域 - 阅读http://www.movable-type.co.uk/scripts/latlong-vincenty.html

第二 - PL / SQL不是一个完美的工具,可以用多行代码进行多次调用来编程计算。如果您使用Java或C ++实现数学运算,您将获得巨大的性能提升。可以像从函数一样从Oracle调用C ++或Java代码。

第三 - 评论说你需要用简单的长方形拳击切出尽可能多的分数的人是非常正确的。按经度和纬度列创建索引,这将有助于执行该装箱子句。

最后,我不认为Oracle Spatial必须参与其中 - 这是一种过度杀伤力。如果您已经拥有并创建了SDO_GEOMETRY列,这是一个故事,但如果没有 - 我不会考虑它。