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

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

1
2
3
4
5
6
where latitude>y-range
and latitude<y+range
and longitude>x-range
and longitude <x+range
order by abs(longitude -x)+abs(latitude -y) 
limit 10;

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

这里有算法

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


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

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

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

1
2
3
4
5
6
7
$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使用空间函数

这里有mysql的空间函数开发文档

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

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

这里的核心思想就是用一个范围判断某个点是否在这个范围内。
在数据库有一个类型为geometry的列g。

1
2
select id,AsText(g) from geom
where MBRContains(GeomFromText('Polygon((x0 y0,x1 y0,x1 y1,x0 y1,x0 x0))'),g);

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

1
2
3
4
5
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),闭合矩形,其实支持任意闭合多边形

1
2
3
4
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。

1
2
3
4
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是将二维的经纬度转换成字符串,字符串长度越长,精度就越精细。俩个字符串长度匹配的位数越多,就越接近,绝大部分情况看起来是这个样子的,但有例外。

类似于:|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经纬度经纬解决方案,如果有更好的方案,欢迎评论区讨论。

本文由程小白创作,本文可自由转载、引用,但需署名作者且注明文章出处。

原文地址http://www.chengxiaobai.cn/SQL/mysql-according-to-the-latitude-and-longitude-search-sort.html

转:mysql根据经纬度查找排序的更多相关文章

  1. 转!!mysql order by 中文排序

    1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...

  2. mysql order by 中文 排序

    mysql order by 中文 排序 1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都 ...

  3. 【中文排序】mysql order by 中文排序

    1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...

  4. mysql按照中文名称排序

    mysql按照中文名称排序   Sql代码  www.2cto.com   /*   Navicat MySQL Data Transfer      Source Server         : ...

  5. 第四篇、C_快速、冒泡、选择、插入排序、二分查找排序、归并、堆排序

    1.快速排序 实现: 1.取中间一个数作为支点 2.分别在支点的左右两边进行查找,如果左边查找到比支点大,右边查找到比支点小,就交换位置,如此循环,比支点小的数就排在了左边,比支点大的就排在右边 3. ...

  6. MySQL查询优化:连接查询排序limit

    MySQL查询优化:连接查询排序limit(join.order by.limit语句) 2013-02-27      个评论       收藏    我要投稿   MySQL查询优化:连接查询排序 ...

  7. Mysql Order By 字符串排序,mysql 字符串order by

    Mysql Order By 字符串排序,mysql 字符串order by ============================== ©Copyright 蕃薯耀 2017年9月30日 http ...

  8. 常见的排序算法(直接插入&选择排序&二分查找排序)

    1.直接插入排序算法 源码: package com.DiYiZhang;/* 插入排序算法 * 如下进行的是插入,排序算法*/ public class InsertionSort {    pub ...

  9. mysql查询根据时间排序

    表数据: mysql查询根据时间排序,如果有相同时间则只查询出来一个 所以需要再判断,如果时间相同,则根据id进行降序排序

随机推荐

  1. 2424: [HAOI2010]订货

    2424: [HAOI2010]订货 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 922  Solved: 642[Submit][Status][ ...

  2. AppBox升级进行时 - 关联表查询与更新(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 关联表的查询操作 使用 Include 方法,我们可以在一次数据库查询中将关联 ...

  3. JS组件系列——开源免费图表组件:Chart.js

    前言:最近被开源免费得有点上火了,各种组件首先想到的就是是开源否.是否免费.是否和bootstrap风格一致.想着以后做报表肯定要用到图表组件的,于是在Bootstrap中文网上面找到了Chart.j ...

  4. php根据地址的经纬度查询周围的城市例子

    目前的工作是需要对用户的一些数据进行分析,每个用户都有若干条记录,每条记录中有用户的一个位置,是用经度和纬度表示的.还有一个给定的数据库,存储的是一些已知地点以及他们的经纬度,内有43W多条的数据.现 ...

  5. JavaScript之命名空间模式 浅析

    来源于:http://www.cnblogs.com/syfwhu/p/4885628.html 前言 命名空间可以被认为是唯一标识符下代码的逻辑分组.为什么会出现命名空间这一概念呢?因为可用的单词数 ...

  6. Local gulp not found in.. on windows

    当出现报错时,请按如下方式安装 gulp 以下使用国内的淘宝镜像安装: $ # Step 1 $ cnpm install -g gulp $ # Step 2 $ cnpm install --sa ...

  7. JQuery对id中含有特殊字符的转义处理

    转载--http://www.jb51.net/article/41192.htm <div id="a[]">kkkkkk</div> <scrip ...

  8. 【转】Java中try catch finally语句中含有return语句的执行情况(总结版)

    Java中try catch finally语句中含有return语句的执行情况(总结版) 有一点可以肯定,finally块中的内容会先于try中的return语句执行,如果finall语句块中也有r ...

  9. miRNA特点

    ### miRNA特点 (1)广泛存在于真核生物中, 是一组不编码蛋白质的短序列RNA,它本身不具有开放阅读框架(ORF),并且由不同于mRNA的独立转录单位表达. (2)通常的长度为20-24 nt ...

  10. C#算法知识点记录

    针对算法的知识点进行记录 简易桶排序 首先看一个简易桶排序,有一串数字,进行从大到小排列.数字间隔不大,使用一维数组来当作桶,进行插入排序. static void Main(string[] arg ...