需求:
已知一个点的经纬度,需要从表中找出以这个点为中心,半径M米范围内的所有经纬度数据。
假设现有表 TAB_LONG_LAT_DATA,字段如下:
ID INTEGER # 点序号
LONGITUDE NUMBER # 经度
LATITUDE NUMBER # 纬度
OTHERS VARCHAR2(20) # 其他信息,不一一例举
已知中心点的经纬度为(119.576051, 25.497901),求半径范围在 500M内的所有经纬度数据?
思路:
要满足需求,我们要知道2个经纬度的距离公式,当这个距离小于M米时,这点即为需要找的点。
方案一:(查询很慢)
1、建立2点的距离公式的函数:
PI,RADIUS为Π和地球半径,计算的距离单位和RADIUS单位一致,可以根据自己的需要设置。
FUNCTION FUNC_DISTANCE(lonA NUMBER, latA NUMBER, lonB NUMBER, latB NUMBER) RETURN NUMBER;
2、根据需求,直接从表中查询结果:
结果发现,在50W的数据量下,查询很慢,需要30s,甚至更高。
方案二:(超快)
1、按照方案一,建立距离函数,同时,根据距离公式,反推以中心点为中心,算出方形范围内(正方形边长=2 * 距离)最大最小经纬度的函数,
返回类型为对象表,字段信息: min_lon, max_lon, min_lat, max_lat
函数需要的对象及对象表:
同时,在原有表中对经纬度字段建立索引:
完整的函数如下:
2、先根据半径范围,把数据缩小到方形范围内的结果集,然后在结果集中计算距离符合的点,优化后的sql如下:
在调试中发现,红框中的对象表,如果不加“ where ROWNUM = 1” 条件,则查询也很慢,查看执行计划,这个对象表查询花费很多资源,但实际单独查询很快,
可能是嵌套问题,加 where条件后,只返回一行,而对象表里面实际也就一行,我们也就只需要这一行,此时执行效率就很快了,基本在1s内。
总结:
通过方案的对比,对于sql查询的where条件需要计算,且没有其他条件来走索引,只能全表扫描时,我们可以换个思路,是否可以把查询范围先缩小,然后在小范围内,再去刷选满足条件的数据,从而达到需求目的。
计算方形范围的最值算法如下:
需要用到的公式:、
具体算法:需要求方形四个角的经纬度
D为距离,R为地球半径, PI, lonA, latA 为已知中心点的经纬度