目的是,根据经纬度,实现查其找附近的人或地点,LBS场景。

做基于地理位置的应用后台,没有使用mongodb,看了网上的很多答案,其实也就是几份答案而已,天下文章一大抄。

这里综合网上的,结合自身,总结出了几种根据经纬度的排序算法,测试可用,性能也还可以。逐步递进优化,不同阶段,不同使用。

这里x为纬度,y为经度。

PS:SQL代码不完整,仅供阅读参考,理解意思就好。

一、MySql不使用空间函数,简单版

1.粗算,根据场景得到一个range,计算经纬度,得到的是一个矩形区域(A),不精确,但是已经有范围这个雏形了,最容易实现的方式之一。

where latitude>y-range

and latitude

and longitude>x-range

and longitude

order by abs(longitude -x)+abs(latitude -y)

limit 10;

2.使用PHP函数计算出距离,排序即可。

排序的话,自己灵活实现。很多语言都有封装排序算法,效率也挺高的。

二、Mysql不使用空间函数,优化版

这里的优化是对(一)中range的优化。根据范围半径,计算出经纬度的变化范围,得到一个比较准确的range,这里的范围(B)是圆形的(因为$radius是俩点间的距离)。

但是筛选时候的范围(C)是矩形,所以精确上来说, 圆B是矩形C的内切圆,不在圆B但是在矩形C中的点也会出现在我们的SQL结果中。但是已经比(一)要好很多了。

$radius = 1;//半径范围,单位km

$rangeLat = 180 / pi() * $radius / 6372.797;//纬度范围

$rangeLng = $rangeLat / cos($x * pi() / 180.0); //经度范围

$maxLat = $x + $range; //x1

$minLat = $x - $range; //x0

$maxLng = $y + $lngR; //y1

$minLng = $y - $lngR; //y0

我见过把这个计算带入到SQL中的,一大串SQL,这种计算本来就不是SQL该有的,不推荐这样做。

三、MySql使用空间函数

在(二)中,我们得到了4个点。这个就是矩形范围,我们只要判断是否在这个矩形内就好了。其实用到mysql的空间函数可以支持任意多边形。

还支持索引优化,MyISAM 才能建立空间索引,MySql 5.7版本 InnoDB 也支持空间索引了。

优化程序将调查可用的空间索引是否能包含在使用某些函数的查询搜索中,如WHERE子句中的MBRContains()或MBRWithin()函数。

--19.6.2. 使用空间索引

这里的核心思想就是用一个范围判断某个点是否在这个范围内。

在数据库有一个类型为geometry的列g。

select id,AsText(g) from geom

where MBRContains(GeomFromText('Polygon((x0 y0,x1 y0,x1 y1,x0 y1,x0 x0))'),g);

即可准确筛选出在这个范围内的点。即使后面跟ORDER BY限制距离性能也没有太大影响。

SELECT id, AsText(g), SQRT(POW( ABS( X(g) - X(x)), 2) + POW( ABS(Y(g) - Y(y)), 2 )) AS distance

FROM geom[*1]

WHERE MBRIntersects(g, GeomFromText('Polygon((x0 y0,x1 y0,x1 y1,x0 y1,x0 x0))'))[*2]

AND SQRT(POW( ABS( X(g) - X(x)), 2) + POW( ABS(Y(g) - Y(y)), 2 )) < radius[*3]

ORDER BY distance;[*4]

1:从geom表中根据俩点间的距离公式计算结果,命名为distance

2:条件1,g列中的点和算出来的范围相交!相交!相交!注意我用的是MBRIntersects(),不是MBRContains()

3:条件2,distance小于给定的半径radius

4:根据distance排序

上面是根据官方文档写的示例代码,比较重要,如果你没看懂,没关系,我来举个栗子

这里选用MBRContains()来举例子,你可以自己实验下MBRWithin()函数,注意参数顺序就好了,我这里得到的结果是一样的。

函数用法:MBRContains(g1,g2)

函数说明:返回1或0以指明g1的最小边界矩形是否包含g2的最小边界矩形

函数已经说明了是g1是否包含g2,所以不要弄反了;这里的矩形支持任意多变形

目标点:D(1,1)

也可以是范围哟,见注释*1

范围:E(0 0,0 3,3 3,3 0,0 0),闭合矩形,其实支持任意闭合多边形

SELECT id,name

from geom

where MBRContains(GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))'),

GeomFromText('Point(1 1)'));[*1]

1:这里的目标点D也支持任意多边形,参数不再是Point()而是Polygon()

这条SQL可以解释为判断点D是否在范围内E。

SELECT id,name,AsText(g)[*1]

from geom

where MBRContains(GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))'),

g);

1:因为g列是geometry类型的,所以要用AsText转换下再展现出来

这条SQL可以解释为列出数据库中所有包含在范围E中的点。

更多相交、包含、接触等方法见上面开发文档 《19.5.5. 关于几何最小边界矩形(MBR)的关系》

四、geohash

这个GeoHash是将二维的经纬度转换成字符串,字符串长度越长,精度就越精细。俩个字符串长度匹配的位数越多,就越接近,绝大部分情况看起来是这个样子的,但有例外。

类似于:(G->)|J......我|K......|(

因为GeoHash是将区域划分为一个个规则矩形,所以在同一个矩形中,GeoHash是一样的,但是会出现一个边际问题:G、H俩个左右相邻的矩形,我在G的右边际处(右边际和H相邻),餐厅J在G的左边际,餐厅K也在H的左边际,通过GeoHash得出来的结果是餐厅J离我更近,显然不合理。

可以通过加大矩形区域的精细程度和扩大相似范围解决。

根据匹配相应的位数,在mysql加入索引,可以极大提高效率。GeoHash和经纬度的转换,网上都有现成的代码,这里不再展示,PHP还有对应的C拓展能提高计算速度。

*在纬度相等的情况下:

*经度每隔0.00001度,距离相差约1米;

*每隔0.0001度,距离相差约10米;

*每隔0.001度,距离相差约100米;

*每隔0.01度,距离相差约1000米;

*每隔0.1度,距离相差约10000米。

*在经度相等的情况下:

*纬度每隔0.00001度,距离相差约1.1米;

*每隔0.0001度,距离相差约11米;

*每隔0.001度,距离相差约111米;

*每隔0.01度,距离相差约1113米;

*每隔0.1度,距离相差约11132米。

Geohash,如果geohash的位数是6位数的时候,大概为附近1千米。

五、Redis GeoHash

Redis也能玩定位?

sure!并且效率奇高!

虽然也是通过GeoHash(高性能、高精度版)来实现的,但是它封装了很多有用的方法,直接使用经纬度即可操作,能直接根据距离返回对应的点,支持直接返回json,还支持排序输出。

毕竟是Redis,持久化和容量都是要考虑的问题。

但是Redis从来不是孤军奋战的工具。

可以和MySql搭配,放在数据库前扛着,里面存储高频定位点,MySql也支持定位(方案三),合理使用应该很好的MySql定位解决方案了。

以上就是根据现有资料整理的MySql经纬度经纬解决方案,如果有更好的方案,欢迎评论区讨论。

happy coding~

mysql按经纬度排序_mysql根据经纬度查找排序相关推荐

  1. mysql按字段值排序_mysql按字段值排序

    1.mysql按字段值的拼音首字母排序 关键词binary :SELECT name FROM topic ORDER BYbinary name asc 2.php获取汉字拼音的第一个字母 直接调用 ...

  2. mysql join 排序_MySQL查询优化:连接查询排序limit(join、order by、limit语句)

    本文链接:https://blog.csdn.net/xiao__gui/article/details/8616224 不知道有没有人碰到过这样恶心的问题:两张表连接查询并limit,SQL效率很高 ...

  3. mysql 排序_MySql的几种排序方式

    MYYA 1.单列排序SELECT * FROM test1 ORDER BY date_time默认升序,降序后面接"DESC"即可.2.多列排序 SELECT * FROM t ...

  4. mysql 汉字字母拼音_mysql 汉字按拼音字母排序、获取拼音首字母、拼音全拼

    一.汉字utf-8 转gbk排序 ORDER BY CONVERT(city_name USING gbk) 二.获取词语拼音首字母 创建函数 CREATE FUNCTION `firstPinyin ...

  5. mysql查询低效语句_MySQL数据库中查找执行从命慢的SQL语句

    MySQL数据库中查找执行从命慢的SQL语句 (2011-09-15 08:21:35) 标签: 杂谈 去历:赛迪网 做者:Alizze 启动Mysql时减参数--log-slow-queries去挤 ...

  6. mysql的select的排序_mysql数据分组和排序及SELECT子句顺序

    mysql分组和排序 虽然 GROUP BY 和 ORDER BY 经常完成相同的工作,但它们是非常不同的.下表汇总了它们之间的差别. 表中列出的第一项差别极为重要.我们经常发现用 GROUP BY ...

  7. mysql 字段名排序_mysql 字段属性 与 排序

    mysql中常见的数据类型:varchar(n).float.int(n).bigint(n).date.datetime.text 字段属性 默认值:DEFAULT '默认值' 非空:NOT NUL ...

  8. mysql 树排序_mysql按树深度排序

    我有表'pe'与列id,名称和lcltyid我有表'wp_exrz_locality_localities'与id,name和parent locality表是树,父级包含另一个位置行的id . pe ...

  9. mysql 中文排序_mysql如何按照中文排序解决方案

    Sql代码 /* Navicat MySQL Data Transfer Source Server : local Source Server Version : 50022 Source Host ...

最新文章

  1. 【Android View事件分发机制】滑动冲突
  2. elasticsearch的索引自动清理及自定义清理
  3. ubuntu11.04 安装sun-java6-jdk_Ubuntu下安装sun-java6-jdk和eclipse
  4. Apache Kafka消息格式的演变(0.7.x~0.10.x)
  5. Linux如何从普通用户切换到root用户
  6. [摘录]第2章 中场谈判技巧
  7. 标准商业计划书大纲模版
  8. 小程序与H5如何混合开发及WEUI那些事
  9. 计算机模拟题操作题错误,计算机模拟试卷操作题答案.doc
  10. 本地编译 全志a33 的步骤
  11. OA系统面试时如何介绍的思路
  12. HTML5期末大作业:电影网站设计——漫威电影(2页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 web学生网页设计作业源码...
  13. python改变图像颜色_通过python改变图片特定区域的颜色详解
  14. CTF网络安全大赛学习笔记1010
  15. C#读写Excel的4种方案(OpenXml、NPOI、EPPlus、Spire.Office)
  16. 华为k662c的虚拟服务器,华为k662c光猫怎么样? 华为K662c拆机技巧
  17. 复杂度分析--时间复杂度
  18. c语言中用age表示年龄的词语,age和aged表示年龄的用法区别
  19. eclipse选择java版本_Eclipse 版本选择
  20. Flexsim AGV

热门文章

  1. 【大学生数学建模竞赛时间一览表】
  2. CreateJS 学习4 动画、TweenJS
  3. 玩客云刷armbian安装php环境_【2020.1.28】玩客云刷Armbian的那些坑
  4. 使用GeoGebra绘制三角形的外接圆和内切圆
  5. 支配树与Lengauer-Tarjan算法
  6. app端分页 简单的分页 java
  7. 你不知道的电脑36个小技巧(纪念2011教师节)
  8. 【循环搜寻法(使用卫兵)】
  9. css 背景渐变 图像_交叉渐变背景图像
  10. pymysql无法访问本地计算机,使用Python和odo模块在mysql上加载csv时出错