一、MySql不使用空间函数,简单版
1.粗算,根据场景得到一个range,计算经纬度,得到的是一个矩形区域(A),不精确,但是已经有范围这个雏形了,最容易实现的方式之一。
1
2
3
4
5
6
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结果中。但是已经比(一)要好很多了。
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使用空间函数
在(二)中,我们得到了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经纬度经纬解决方案,如果有更好的方案,欢迎评论区讨论。
本文由程小白创作,本文可自由转载、引用,但需署名作者且注明文章出处。
转!!mysql order by 中文排序
1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...
mysql order by 中文 排序
mysql order by 中文 排序 1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都 ...
【中文排序】mysql order by 中文排序
1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...
mysql按照中文名称排序
mysql按照中文名称排序 Sql代码 www.2cto.com /* Navicat MySQL Data Transfer Source Server : ...
第四篇、C_快速、冒泡、选择、插入排序、二分查找排序、归并、堆排序
1.快速排序 实现: 1.取中间一个数作为支点 2.分别在支点的左右两边进行查找,如果左边查找到比支点大,右边查找到比支点小,就交换位置,如此循环,比支点小的数就排在了左边,比支点大的就排在右边 3. ...
MySQL查询优化:连接查询排序limit
MySQL查询优化:连接查询排序limit(join.order by.limit语句) 2013-02-27 个评论 收藏 我要投稿 MySQL查询优化:连接查询排序 ...
Mysql Order By 字符串排序,mysql 字符串order by
Mysql Order By 字符串排序,mysql 字符串order by ============================== ©Copyright 蕃薯耀 2017年9月30日 http ...
常见的排序算法(直接插入&;选择排序&;二分查找排序)
1.直接插入排序算法 源码: package com.DiYiZhang;/* 插入排序算法 * 如下进行的是插入,排序算法*/ public class InsertionSort { pub ...
mysql查询根据时间排序
表数据: mysql查询根据时间排序,如果有相同时间则只查询出来一个 所以需要再判断,如果时间相同,则根据id进行降序排序
随机推荐
转:YUV RGB 常见视频格式解析
转: http://www.cnblogs.com/qinjunni/archive/2012/02/23/2364446.html YUV RGB 常见视频格式解析 I420是YUV格式的一种,而Y ...
linux中文件I/O操作(系统I/O)
我们都知道linux下所有设备都是以文件存在的,所以当我们需要用到这些设备的时候,首先就需要打开它们,下面我们来详细了解一下文件I/O操作. 用到的文件I/O有以下几个操作:打开文件.读文件.写文件. ...
微信小游戏爆款秘笈 数据库MongoDB攻略篇
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云数据库 TencentDB 发表于云+社区专栏 随着微信小游戏的爆发,越来越多开发者关注到MongoDB与小游戏业务的契合度. ...
导入虚拟机vmware,此主机支持Intel VT-x,但Intel VT-x处于禁用状态和黑屏
解决方法:进入BIOS(按什么键进入bios,需要看你用什么电脑),把Intel Virtualization Technology 设置enabled 然后是黑屏解决方法:管理员模式 ...
C++笔记之关键字explicit
在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换. explicit使用注意事项: explicit 关键字只能用 ...
bootstrap treeview实现菜单树
本博客,介绍通过Bootstrap的treeview插件实现菜单树的功能. treeview链接:http://www.htmleaf.com/Demo/201502141380.html ORM框架 ...
mysql where in形式存储过程如何传递带有单引号的入参
对于存储过程或者函数,我们通常都有这样的一个需求,传递一个参数,输出一个结果.如:我传递一个账号,返回这个账号所拥有的权限.但是如果这个需求改了,我要传递多个账号,获取这些账号权限,但是账号的个数不限 ...
[MeetCoder] Crossing Bridge
Crossing Bridge Description N people wish to cross a bridge at night. It’s so dark around there that ...
Struts动态表单(DynamicForm)
动态表单的含义是不要手动定义,直接在配置文件中进行定义. 1.手动进行定义