探索和学习MySQL中GIS相关功能和特性

探索流程:

这里记录了学习和了解MySQL中GIS特性相关内容的过程。

配置了一台用于测试的MySQL Server 5.7

在浏览官网的过程中了解到一个GUI工具:MySQL Workbench,很好玩

开始了解GIS相关内容,但是百度不到很详细的介绍和相关内容

访问MySQL官方论坛,找到了很多很好的内容,但是都TM是英语。

了解到需要用到测试数据,都推荐OpenStreetMap,遂前往了解。OSM官网可以下载部分地图数据或者打包下载中国数据,数据格式不同。中国数据.PBF使用上较繁琐,区域数据.OSM可是通过记事本打开(其实可以当作XML文件内容即可)。

了解到地图数据大多采用一些像PostgreSQL、PostGIS、MongoDB等或Redis之类的NoSQL存储地理位置信息和检索,此类数据库多有GIS相关的处理函数和方法。

了解到地理位置信息的数据结构多采用OSM的通用数据结构。但是也可以变通。

在MySQL官方论坛找到一个例子,了解到可以用过一个数据导入脚本将OSM的数据直接导入MySQL数据库,并且此脚本会自动根据经度和纬度生成geometry列,并能对此列添加spatial index。但是这玩意儿需要Perl语言,WTF。

下载Perl并安装,这玩意儿分为官网版和所谓社区版,官网版就是全部的开源和商业功能的安装包,社区版又叫草莓,是完全的开源功能的安装包,抱着试试看的态度,直接下载草莓传送门。安装成功后,CMD输入perl -v有输出版本信息表示安装成功。

下载网友自行修改的OSM导入脚本传送门,用RAR解压,将OSM目录放置到Perl的安装目录下的perl\site\lib\下即可。

在修改了导入脚本osmdb.pm后终于成功导入了osm数据。

开始正式学习:

测试数据已经导入成功,下面开始对GIS相关函数和GEOHASH进行了解和体验;

geometry(几何类型)

经纬度信息存储在geometry格式的字段中,该字段必须非空。

MySQL8.0前按照longitude-latitude的顺序存储位置

MySQL8.0前按照longitude-latitude的顺序存储位置

MySQL8.0前按照longitude-latitude的顺序存储位置

插入数据时候可使用如下语句:

使用geomfromtext()内置函数可将字符串的位置点转换为geometry格式存入到数据库中,例如:

insert into XXTABLE values (XX,XX,XX, st_geomfromtext('point(108.949871515 34.25416521),XX,XX)

建立geometry的空间索引,便于之后的查询:

创建按geom列的索引,索引类型选择spacial即可;

创建虚拟列geomhash,精度为8位,表达式为st_geohash('GEOM列名',8);

创建虚拟列geomhash的索引。

Geometry数据组成:

MySQL存储geometry信息的方式采用了25bytes,相比WKB的21bytes,多了4bytes的坐标系表示,组成部分如下:

4bytes整形,表示SRID(空间引用标识符,坐标系WGS84,GCJ02等)

1byte整形(同WKB),表示字节顺序

4bytes整形(同WKB),表示数据类型(点、线、面等)

8bytes双精度(同WKB),表示X坐标

8bytes双精度(同WKB),表示Y坐标

ST_GeomFromText

WTF字符串格式说明

select ST_GeomFromText(WTF格式字符串);

WKT(Well-known text)是一种文本标记语言,用于表示矢量几何对象、空间参照系统及空间参照系统之间的转换。通过WTF字符串生成geometry的方法:

点:POINT(x y)

线:LINESTRING(x1 y1, x2 y2, x3 y3...)

多边形:POLYGON((0 0, 10 0, 10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))

多点集:MULTIPOINT(0 0, 20 20, 60 60)或MULTIPOINT((0 0),(5 5),(5 0))

多线集:MULTILINESTRING((10 10, 20 20), (15 15, 30 15))

多多边形集:MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((5 5,7 5,7 7,5 7, 5 5)))

例如两点一线组成的几何集:GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))

MySQL中Geometry的格式约定:

A geometry is syntactically well-formed if it satisfies conditions such as those in this (nonexhaustive) list:

Linestrings have at least two points

Polygons have at least one ring

Polygon rings are closed (first and last points the same)

Polygon rings have at least 4 points (minimum polygon is a triangle with first and last points the same)

Collections are not empty (except GeometryCollection)

其他ST_XXXXFromText函数

更多内容参见

ST_PointFromText('POINT(X Y)');

ST_LineStringFromText('LINESTRING(0 0,1 1,2 2)');

ST_PolygonFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))');

ST_GeomCollFromText();

其他ST_XXXXFromWkb函数

MySQL独有的创建Geometry函数

参见

Point(x,y)

LineString((x1,y1),(x2,y2)...)

Polygon(LineString(),LineString()....)

查询和转换Geometry:

参见

ST_AsText()

ST_AsBinary()

ST_AsWKT()

通用属性函数:

参见

ST_Dimension(geom):返回geom的维度(-1,0,1,2)

ST_Envelope(geom):返回geom的最小外接矩形(MBR)

ST_GeometryType(geom):返回geom的类型

ST_IsEmpty(geom):该函数并不能真实的判空,当geom为任何有效的几何值时返回0,无效的几何值返回1;

ST_IsSimple(geom):当geom无任何异常几何点返回1(如自相交和自切线等),否则返回0

ST_SRID(geom):返回geom的坐标系ID

Point属性函数:

参见

ST_X(Point):获取Point的X值

ST_Y(Point):获取Point的Y值

LineString属性和MultiLineString属性函数

参见

ST_StartPoint(linestrng): 线的起点

ST_EndPoint(linestring):返回线的最后一个点

ST_IsClosed(linestring或multilinestring):线是否闭合(若为线,则判断起点与终点是否一致;若为线组,则判断组内每个元素是否符合闭合线)

ST_Length(linestring):返回线的长度,若入参为线集,则返回集合内所有长度的和

ST_NumPoiints(linestring):返回点的数量;

ST_PointN(linestring,N):返回第N个点(从1开始)

Polygon属性和MultiPolygon属性函数:

参见

具体不在一一列举,主要有计算多边形面积、中心点、最小外接圆,最大内接圆等函数,列举几个可能会用到的:

ST_Area(Poly|mPoly):返回双精度的面积或面积的和

'ST_Centroid(Poly|mPoly)':返回数学上的中心点

ST_ExteriorRing(Poly):返回外接圆

Spatial Operator Functions

参见

ST_Buffer说明

不再列举,主要有:ST_Buffer(不懂干啥用),ST_ConvexHull(geom)凸包,ST_Dfference(g1,g2)比较差异,ST_Intersecton(g1,g2)交叉点,ST_SymDifference(g1,g2)对称差分,ST_Union(g1,g2)连接、合并等。

Spatial Relatiion Functions

检查geometry Objects之间的空间关系的方法。

通过Object自己的形状进行关系检查:

参见

计算两个Object之间的空间关系的函数,有两个间距离、相交、不相交,包含、相等、相切、重叠、接触、在内等等空间关系。下面列举几个可能会常用的方法:

ST_Contains(g1,g2):g1是否完全包含g2

ST_Within(g1,g2):g1是否包含于g2中

ST_Distance(g1,g2):返回g1和g2之间的距离,已坐标单位计算的

ST_Equals(g1,g2):返回g1和g2是否相等

通过最小外接矩形MBR进行关系检查:

参见

MBRContains(g1,g2):g1的mbr是否包含g2的mbr

MBRWithin(g1,g2):g1的mbr是否在g2的mbr内

MBRCoveredBy(g1,g2):g1的mbr是否被g2的mbr覆盖

MBRCovers(g1,g2):g1的mbr是否覆盖g2的mbr

MBRDisjoint(g1,g2):g1的mbr,g2的mbr是否不相交

MBRIntersects(g1,g2):g1mbr,g2mbr是否相交

MBREqual(g1,g2):g1的mbr,g2的mbr的外接是否相等

MBREquals(g1,g2):g1的mbr,g2的mbr的外接是否相等

MBROverlaps(g1,g2):g1mbr、g2mbr

其他函数请参看原文

GeoHash

geohash字段是把坐标系分成很多小方格,然后将经纬度转化成字符串。GeoHash是把经纬度转成字符串,建表的时候让它转成8位字符,当两个点离得越近时,它生成的geohash字符串前面相同的位数越多,所以在这里先用left()截取前6位字符,前6位相同的误差在±600米左右,然后模糊查询,查出大概符合条件的数据,最后再精确比较,下面是geohash官方文档对geohash长度和距离误差的说明:

length

lat bits

lng bits

lat err

lng err

km err

1

2

3

±23

±23

±2500

2

5

5

±2.8

±5.6

±630

3

7

8

±0.70

±0.70

±78

4

10

10

±0.087

±0.18

±20

5

12

13

±0.022

±0.022

±2.4

6

15

15

±0.0027

±0.0055

±0.61

7

17

18

±0.00068

±0.00068

±0.076

8

20

20

±0.000085

±0.00017

±0.019

注意:用geohash 查询会有边界问题,所以查询出来的结果可能不准确,可以用程序(例如java代码)先查出当前点周围8个范围的geohash值,然后再匹配这9个范围的所有数据,这样就解决了geohash 的边界问题。

st_geohash:

MySQL中自带函数st_geohash(longtude,latitude,max_length)或st_geohash(point, max_length)即可生成某一点的geohash值。

其中max_length的最大值为100,经纬度也不能超出范围,否则报错。

设定max_length后产生的hash值也可能会小于此值,即不超过这个长度。

st_LatFromGeoHash,st_LongFromGeoHash

返回一个geohash字符串中的latitude或longitude

st_PointFromGeoHash

返回一个geohash解析出的point数据

geojson

geojson是一个通用的描述位置信息的json格式。具体请参见

st_AsGeoJSON

通过geometry生成一个GeoJSON Object,select st_asgeojson(geometry,max_length,options);

max_length默认不指定,如果指定则返回小数点后的指定长度

其中options参见文档,具体可以是多个选项相加,默认为0

st_GeomFromGeoJSON

通过GeoJSON生成GeoMetry对象。

ST_GeomFromGeoJSON(jsonstring, [options [, srid]])

具体使用方法参见官方文档

Spatial Convenience Functions

官方文档

MySQL中提供的方便空间运算的函数们

ST_Distance_Sphere

select ST_Distance_Spher(geomPoint1,geomPoint2 [, radius]);

此方法用于计算两点或多个点之间的地球上的距离(是地球球面距离而不是直线距离),返回单位为米,

默认的radius半径为6370986米,即地球的半径,也可指定其他半径,单位是米

入参可为(Point,Point),(Point, MultiPoint),(MultiPoint,Point)

ST_IsValid

select ST_IsValid(ST_GeomFromText('LINESTRING(0 0,1 1)'))

判断入参是否是符合地理位置描述的格式。返回1(符合)或者0(不符);

例如:

返回0:

select st_isvalid(st_geomfromtext('linestring(0 0, -0.00 0, 0.0 0)')

返回1:

select st_isvalid(st_geomfromtext('linestring(0 0,1 1)')

ST_MakeEnvelope

select st_astext(st_makeenvelope(pt1, pt2));

返回两点构成的包络。(此计算是基于笛卡尔坐标系而非球面)

如果P1和P2相同,则返沪的是P1

如果P1和P2是垂直或者水平线,则返回结果是线段(P1,P2)

否则,返回结果是P1和P2作为对角线的多边形包络

例如:

SELECT ST_AsText ( st_makeenvelope ( st_geomfromtext ( 'point(0 0)' ), st_geomfromtext ( 'point(1 1)' ) ) );

返回结果:

POLYGON((0 0,1 0,1 1,0 1,0 0))

ST_Simplify

效果说明

JS抽稀算法

select st_simplify(geometry, max_distance);

用道格拉斯-普克算法(抽稀函数)简化geometry,并返回与原格式相同格式的结果。

入参geometry是一个geometry对象(一般为点集合,线)

max_distance为简化步长

例如,以下点集拟合为直线,步长0.5:

SELECT st_simplify ( st_geomfromtext ( 'LINESTRING(0 0,0 1,1 1,1 2,2 2,2 3,3 3)' ), 0.5 )

返回结果:

LINESTRING(0 0, 0 1, 1 1, 2 3, 3 3)

再如,步长1.0:

SELECT st_simplify ( st_geomfromtext ( 'LINESTRING(0 0,0 1,1 1,1 2,2 2,2 3,3 3)' ), 1.0 )

返回结果:

LINESTRING(0 0, 3 3)

ST_Validate

SELECT ST_Validate(geometry);

验证geometry是符合正确的地理位置信息格式。例如Point(0 0)是合格的;Linestring(0 0)是非法的;Linestring(0 0, 1 1)是合格的

应用与实践

了解了上述MySQL中关于集合对象的功能,下面来实践一下

计算两点之间的距离:

SELECT floor(

st_distance_sphere (

( SELECT geom FROM nodestest WHERE id = '151024809' ),

( SELECT geom FROM nodestest WHERE id = '151027929' )

)

);

查找距离某点【POINT(118.9515 34.4271)】500米范围内的点(ST_Distance_Sphere精确查询)

查找耗时约2.582秒。

SELECT

id,

ST_ASTEXT(geom) point,

FLOOR(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(118.9515 34.4271)'),

geom)) distance

FROM

nodestest

WHERE

ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(118.9515 34.4271)'),

geom) < 500

ORDER BY distance;

HASH查找距离某点【POINT(118.9515 34.4271)】500米范围内的点(GeoHash模糊查找后再筛选)

由上面geohash长度-精度对应表可知,前6位表示±610米左右的误差,这里先查询前六位范围之后再用上述方法精确筛选一次即可:

查找耗时约0.016秒

SELECT

t.id,

ST_ASTEXT(t.geom) point,

FLOOR(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(118.9515 34.4271)'),

t.geom)) distance

FROM

(SELECT

id, geom, ST_ASTEXT(geom) point

FROM

nodestest

WHERE

geomhash LIKE (CONCAT(LEFT(ST_GEOHASH(118.9515, 34.4271, 8), 6), '%'))) T

WHERE

ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(118.9515 34.4271)'),

t.geom) < 500

ORDER BY distance;

可将上述查询方法封装为MySQL函数方便和简化程序调用.

通过几何关系函数查找距离某点【POINT(118.9515 34.4271)】500米范围内的点

该方法是运用了内置的几何关系运算函数ST_Contains和ST_MakeEnvelop来实现的,0.5对应大概500米左右的范围,具体如下;

耗时0.016s

SELECT

id,

ST_ASTEXT(geom),

FLOOR(ST_DISTANCE_SPHERE(POINT(118.9515, 34.4271), geom)) AS distance

FROM

nodestest

WHERE

ST_CONTAINS(ST_MAKEENVELOPE(POINT((118.9515 + (0.5 / 111)),

(34.4271 + (0.5 / 111))),

POINT((118.9515 - (0.5 / 111)),

(34.4271 - (0.5 / 111)))),

geom)

ORDER BY distance

思考与讨论

关于社区地理位置的存储,是否可改用Polygon()存储,并建立一列生成列,通过函数ST_Centroid(ST_ExteriorRing(polygon))的方式,把区域的外接圆的中点当作区域的中点,或直接把区域的几何中点作为中点

查找附近的小区,可使用哪几种方法?

测试用例和导入脚本可自行下载(比较老了,可能官网早已经更新)

mysql gis_MySQL的GIS、GEO入门笔记相关推荐

  1. MySql入门笔记二~悲催的用户

    这些是当年小弟的MySql学习笔记,木有多么复杂的结构操作,木有多炫丽的语句开发,木有...总之就是木有什么技术含量... 日复一日,彪悍的人生伴随着彪悍的健忘,运维操作为王,好记性不如烂笔头,山水有 ...

  2. mysql入门到跑路_MySQL 24小时入门笔记(3),插入和删除,删库到跑路

    MySQL 24小时入门笔记 插入 INSERT INSERT用法非常简单.现在我们有表students如下. 列名 类型 约束 id int primary key name char(16) NO ...

  3. 【mysql入门笔记01 2022.9.27】

    mysql入门笔记01 2022.9.27 数据库概念 数据库管理系统 关系型数据库(RDBMS) 非关系型数据库(NoSQL) SQL概念 Mysql 版本 Mysql安装 Mysql启动 方式一 ...

  4. MySql 数据库入门笔记

    -- 数据库入门笔记   -- 我来入个门 CREATE DATABASE db; -- 使用数据库 USE db; -- 创建表 CREATE TABLE t(     tid DECIMAL(4, ...

  5. Shiro 入门笔记,整合SpringBoot,Redis

    Shiro 入门笔记 视频地址:https://www.bilibili.com/video/BV1uz4y197Zm 感谢编程不良人的教程 1. 权限管理 权限管理包括用户 身份认证 和 授权 两部 ...

  6. ArcEngine C# GIS开发入门作业 (三)Ex04——实现地图的简单渲染和唯一值渲染

    文章评论 写评论 sinat_37432938: 可以说非常有参考的意义,谢谢分享 4周前 #2楼 举报回复查看回复(1) domen_dragon 回复 sinat_37432938: 哈哈,谢谢夸 ...

  7. onethink入门笔记(一)

    onethink入门笔记(一) 由于公司需求所以大概花了一个星期搞了一个一个基于onethink的数据管理平台demo不得不说onethink这个基于thinkphp3.2.3的框架还是很棒的 让我这 ...

  8. SpringBootShiro入门笔记

    shiro入门笔记 第一章 Shiro简介 1.1 什么是Shiro? 1.2 Shiro框架结构 1.2.1 Shiro主要三大核心注件 1.2.2 主要功能 第二章 认证 2.1 新建一个spri ...

  9. Koa2入门笔记 (上)

    感谢一个不打荣耀的大神教会我使用Koa写接口 简单快速撸懂MySQL+Koa2_哔哩哔哩_bilibili 再也不必害怕后端不能沟通了,学会了还可以自己做喜欢的项目来玩 这里就是课堂笔记 哎呀!!真是 ...

最新文章

  1. 利用frp进行内网穿透
  2. Android之自定义标题
  3. 强大的PHP防SQL注入类,可以过滤敏感参数
  4. 一文搞懂C语言typedef关键字
  5. java通过spring获取配置文件_springboot获取properties文件的配置内容(转载)
  6. NetBeans 时事通讯(刊号 # 134 - Jan 25, 2011)
  7. 五)Spring + Quartz 复杂业务的两个问题:获取Spring上下文 和 自动注入服务类
  8. 电容的q值计算公式_在设计电路中电容容量大小、耐压等级选取详解 (转)
  9. 04.自定义View(SlidingView仿QQ侧滑)
  10. 雨松MOMO《Unity 3D游戏开发》源码公布
  11. Cacti脚本及模板---PING
  12. 基于Spark的电影推荐系统实现
  13. 微信小程序快速达到1000UV流量主开通标准
  14. #从焦虑到从容,不吼不叫养出好孩子-02做懂得沟通的父母-带着爱与慈悲来表达需求
  15. Qt,C++ 仿MAC桌面程序,DOCKBAR
  16. python从字符串中提取指定的内容
  17. 计算机语言的魅力,四年级语文下册《语言的魅力》说课稿
  18. 如何进行网站诊断呢?
  19. The user name or passphrase you entered is not correct for Mac Xcode
  20. 房贷利率下调 现在是买房的时机吗?

热门文章

  1. FPGADesigner《FPGA数字信号处理系列》目录与传送门
  2. jdk11新特性——ZGC
  3. 计算机网络的发展历史
  4. linux sda sdb 问题 .
  5. Python快速入门 满满都是干货!
  6. DataX数据交换,starrockswriter异常解决
  7. parseInt转换
  8. sfsfdgsdfg
  9. ADC 信号调理电路设计——必要措施、实测验证和应用说明
  10. PADS2007下快速布局布线PCB_本人总结