设为首页 收藏本站
查看: 596|回复: 0

[经验分享] 3分钟了解Mysql空间搜GeoHash

[复制链接]

尚未签到

发表于 2017-11-13 14:39:31 | 显示全部楼层 |阅读模式
简单介绍:
   Mysql 内置函数方案,适合于已有业务,新增加LBS功能,增加经纬度字段方可,避免数据迁移,在5.7.5后实现更多功能实现INNODB的空间搜方法,之前版本主要是对MYISAM的支持。
    在此之前,InnoDB将几何数据存储为BLOB(二进制大对象)数据,在空间数据上只能创建前缀索引,当涉及空间搜索时非常低效,尤其是在涉及复杂的几何数据时。在大多数情况下,获得结果的唯一方式是扫描表。
    新版本MySQL中,InnoDB支持空间索引,通过R树来实现,使得空间搜索变得高效,如使用内置函数(MBRWITHIN MBRCONTAINS)效率非常好。但目前空间索引只支持两个维度的数据。

应用场景介绍:
    公司新业务的需求,希望能够实现当前位置快速显示共享信息数据,针对5.7新特性的支持度调研,利用GeoHash封装成内置数据库函数的简易方案,实现前期的初期业务。
实现过程:
  1、构建表
    CREATE TABLE `tongzhou` (
      `id` INT(11) NOT NULL AUTO_INCREMENT,
      `cname` VARCHAR(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
      `oint` POINT NOT NULL,
      PRIMARY KEY (`id`),
      SPATIAL KEY `sp_index` (`oint`)
    ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  2、构造简单数据
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('景欣园 ','POINT(39.8885917679 116.6576038966)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('京通罗斯福广场','POINT(39.8890214887 116.6473661241)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('中国北京市北京市通州区','POINT(39.8898670523 116.6566729546)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('中国北京市北京市通州区','POINT(39.8883852752 116.655728817)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('杨庄路22号院','POINT(39.8984936518 116.6339063644)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('中国北京市北京市朝阳区 ','POINT(39.8975388526 116.613779068)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('北京市朝阳区第三医院 约31米','POINT(39.8873809413 116.603307724)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('双桥温泉北里小区','POINT(39.8918427053 116.6076636314)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('京客隆配送中心','POINT(39.8916616061 116.5908622742)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('世纪宾馆','POINT(39.8918591688 116.6024065018)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('双桥六号井小区-北区 约48米','POINT(39.8899164443 116.6050457954)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('翠屏里小区 约190米','POINT(39.8883194176 116.6495060921)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('京通罗斯福广场','POINT(39.8894719148 116.6584646702)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('life新生活广场 约87米','POINT(39.8895542353 116.65579319)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('life新生活广场 约74米','POINT(39.8896242077 116.6568982601)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('life新生活广场','POINT(39.8901428239 116.6564154625)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('漫春园','POINT(39.8913364496 116.658115983)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('7天连锁酒店(北京通州果园环岛店) 约58米','POINT(39.8915998677 116.6560935974)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('北京金松宾馆 约77米','POINT(39.9036172391 116.6577833891)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('新华南路小区-东区 约32米','POINT(39.9034444015 116.6588240862)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('红旗小区 约61米','POINT(39.9046707164 116.6598540545)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('祥云天地家园 约62米','POINT(39.9067899674 116.659129858)');
    insert into `tongzhou` (`cname`, `ASTEXT(oint)`) values('梨园地铁站 约40米','POINT(39.8832975966 116.6687965393)');

  3、搜索当前1公里范围内的位置信息
    SET @jl=1;  //多少公里范围内的
    SET @jd=118.1964111328;
    SET @wd=39.5591182422;  //当前的位置信息
    oint是实际已经存在的经纬度信息
     SELECT *,ASTEXT(oint)FROM  tongzhou WHERE  MBRCONTAINS( LINESTRING(POINT( @wd + @jl / ( 111.12 / COS(RADIANS(@jd))),
    @jd + @jl / 111.12  ),  
    POINT  ( @wd - @jl / ( 111.12 / COS(RADIANS(@jd))),@jd - @jl / 111.12)  ), oint)
    ###经纬弧度(1° latitude = 111.12 kilometers)即 10/111.12,表示查找附近10公里。
  4、测试
    通过百度地图获取一些数据,对
         SET @jd=118.1964111328
         SET @wd=39.5591182422
        值的更新,分析获取范围内的景点信息

  5、问题:
     如果直接在WHERE采用一系列的表达式,这样会导致无法使用空间索引,如图所示:
2fa268136801e296920360f50ace6d02.png-wh_500x0-wm_3-wmp_4-s_2852158178.png
解决办法:
     1、把WHERE后的表达式处理成一个变量进行引用,然后进行周边搜   
    SET @aa=(SELECT LINESTRING(POINT( 39.5591182422 + 10/ ( 111.12 / COS(RADIANS(118.1964111328))),
    118.1964111328 + 10 / 111.12  ),  
    POINT  ( 39.5591182422 - 10 / ( 111.12 / COS(RADIANS(118.1964111328))),118.1964111328 -10 / 111.12)) AS  heji)
     2、执行周边搜
       SELECT ASTEXT(oint)FROM  tongzhou WHERE  MBRWITHIN(@aa,oint)
   顺带执行计划效果:
       052ca10b26528e25d9ca6f86d428f596.png-wh_500x0-wm_3-wmp_4-s_39204127.png

拍砖了。。。。。。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-407034-1-1.html 上篇帖子: MySQL存储引擎MyISAM与InnoDB的区别 下篇帖子: MySQL日志简介
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表