目前,我已经实现了一个距离函数(基于haversine公式),但由于数据库有点大,每次查询需要花费约50秒。
您有什么关于如何高效处理此问题的建议吗?我知道有一个名为Oracle Spatial & Locator的扩展程序,但我不知道是否可以购买,甚至不知道它是如何工作的。非常感谢您的帮助。最好的问候。
如果您还没有这样做,以下是一些建议...
由于Haversine计算需要弧度角,如果您将纬度和经度存储为度数,请添加几列并预先计算弧度等价物。更一般地说,请预先计算公式中可以的任何值并存储它们。
考虑使用一个简单的函数来消除半径外部的点,仅对那些基于简单函数可能匹配的点运行Haversine函数。对于度数,您可以使用SQRT ((69.1 * dLat)2 + (53 * dLong)2))并使用一些调整因子(10%)。如果您需要比较精确的结果,则仅在与较粗的近似值匹配的点上运行Haversine计算。
"特定距离"是否有些恒定?即您是否总是在搜索 "范围内所有点1英里",还是半径会改变?
您预计在任何给定查询中将获得多少百分比的总记录?10%?.10%?
如果您始终具有相同的半径,请构建具有与半径相同长度的方形网格。分配每个邻近方格的列表。每个点将知道它在哪个正方形中,从中您可以获得所有相邻正方形的列表。然后仅在这些正方形中运行计算。这类似于其他答案出现的答案,但速度更快,因为线性计算是通过索引查找近似计算而不是在每个点之间进行计算。
即使使用可变的半径,仍然可以使用上述方法,但您必须计算要包括多少“邻居”。仅在从任何单个查询中获取总数的一小部分时才可行。
如果您不需要距离太精确,可以将地球视为平面。来自此讨论:
Approximate distance in miles:
sqrt(x * x + y * y)
where x = 69.1 * (lat2 - lat1) and y = 53.0 * (lon2 - lon1)
我最近对mysql进行了一些优化(在这里概述:www.mooreds.com/wordpress/archives/000547 [抱歉,每篇文章只能有1个超链接]),但不确定我所经历的步骤中有多少适用于Oracle。其中一些肯定是适用的(例如尽可能使用边界框)。
Approximate distance in miles:
sqrt(x * x + y * y)
where x = 69.1 * (lat2 - lat1) and y = 53.0 * (lon2 - lon1)
如果您将53.0的魔法数字更改为考虑到纬度变化(向极地移动时逐渐变小),则可以获得更准确的结果。
有人知道这个神奇的公式吗?
首先,Haversine并不完美,因为地球不是一个完美的球体 - 请阅读http://www.movable-type.co.uk/scripts/latlong-vincenty.html
其次,PL/SQL不是用于编写需要被多次调用的多行代码计算的完美工具。如果您使用Java或C++实现数学计算,将会获得巨大的性能提升。C++或Java代码可以像函数一样从Oracle中调用。
第三,那些评论说您需要通过简单的矩形框选尽可能多的点是非常正确的。通过经度和纬度列创建索引,这将有助于执行该框选子句。
最后,我认为Oracle Spatial在这里没有必要 - 这是一种过度杀伤力的做法。如果您已经拥有它并创建了SDO_GEOMETRY列,则是另一回事,但如果没有 - 我不会考虑它。