mysql查找附近优化思路

场景 :
各种LBS的应用,例如滴滴打车,转转,微信,qq我周围的朋友,以及地图中各种poi搜索等。
mysql 计算两点的距离很复杂,如果数据量很大,会导致等待时间过长,这是远不能接受的,目前我的思路主要分为两点 1是优化搜索速度,2是降低cpu的占用率,提高cpu的使用率,提高最大并发量

一. 优化查询速度

思路就是一,怎么使用索引,如何缩小范围

缩小范围思路 :

1.按照地区进行缩小范围

例如中国,就比全球要小,北京又比中国要小,甚至精确到某个区,县等

2.通过geohash算法,创建索引

其实就是通过一种编码方式,将二维的经纬度转换为一维的,类似于那将整个地球划分成4000 * 4000,每个格子再划分成10 * 10,最终的粒度是1公里*1公里,这样,我们就可以对这个一维的数据创建索引进行查询,网上搜索一下很多这方面的知识,这里不细说,参考GeoHash核心原理解析

上面所说的只是优化速度,只是找出附近,不能排序,无论按照高中的知还是google推荐的算法,查两点的经纬度都很复杂

二. 减少计算复杂度,降低cpu的消耗

方法一: 坐标转换法
考验自己的数学啊,我是自己推了好久
设有两点A B ,坐标分别为 (lat1,lng1) (lat2,lng2),地球中心点为O,地球半径为R=3979
假如B点是数据库中存好的,A点是根据用户所在地取出来的,那么,网上最常见的计算距离的方法如下,(下面方程高中内容,不再证明)

AB弧度=3979*△AOB=3979*arccos(cos△AOB)=
3979arccos{ cos(lat1)cos(lat2)cos(lng2-lng1)+sin(lat1)sin(lat2)}

我们对大括号里面的进行分解,得到:

cos(lat1)cos(lat2)cos(lng2-lng1)+sin(lat1)sin(lat2)=
cos(lat1)cas(lng1)*cos(lat2)cos(lng2)+cos(lat1)sin(lng1)cos(lat2)sin(lng2)+sin(lat1)sin(lat2)

注意我标记的部分,此时,我们可以对数据库加三列,把经纬度坐标这两列给去掉,数据库保存的是经过下面的公式计算过的

x=cos(lat)cos(lng)
y=cos(lat2)sin(lng2)
z=sin(lat2)

那么这两点的距离就是

3979arccos(x1*x2+y1*y2+z1*z2)

对于arccos函数在-1到1单调递减
arccos函数
arccos的函数,-1到1是单调递减函数,在最下面有附录:
其实也很显然AOB的角度越小两点距离越近

假如我们的需求是只需要取前20个最近的post。所以,我们只需要找出 x1*x2+y1*y2+z1*z2,这种计算对于数据库中cpu的占用是非常小的,我查出最大的20个值即可
然后再去程序中,计算3979*arc(取出的20个值)。程序中只需计算20次arc的函数,是非常快的
这里不再需要使用估算,不再使用sqrt,数据库中只是计算乘法,经过一些措施减少查询的条数,这种查询占cpu是非常少的

其他的一些办法

  1. 根据某些特点区域的经纬度,我们知道每一经度大概的距离,每一纬度大概的距离,然后,地球上两点,就可看成平面,勾股定理就可以了。在特点场合,这种效率很高,准确率也还可以,甚至,我们可以直接经度上的距离,加上纬度上的距离,这样不是非常准确,对于不是非常高准确率要求的,我们可以直接做
    例如我们可以用三阶去方程拟合cos,没一纬度110公里,每一经度110公里*cos纬度
    如何拟合参考: http://blog.csdn.net/T1DMzks/article/details/69267678

  2. 直接对整个地球(或者你业务所在的某个区域)进行区域的划分,每一个区域指向一些你要查找的经纬度的点,我们都可以建立索引,用户一处于这个区域,就把这个区域的所有点给取出来,这种方法的优点是快,缺点是前期需要做很大的处理工作,其实这类似与geohash

发布了137 篇原创文章 · 获赞 211 · 访问量 58万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览