MySQL 8.0.23 空间数据类型(Spatial Data Type)

目录

    • 1. MySQL空间数据类型的基本介绍
      • 1.1 什么是MySQL空间数据类型
      • 1.2 有哪些空间数据类型
      • 1.3 支持空间数据类型的引擎
      • 1.4 坐标系类型
    • 2. 存储坐标系的示例代码
      • 2.1 `geomtry`和`point`都可以存储坐标系,有什么区别呢?
      • 2.2 创建测试表
      • 2.3 新增坐标
      • 2.3 计算两地之间的距离
      • 2.5 列举距离我5km内的地址

1. MySQL空间数据类型的基本介绍

MySQL空间数据类型官方文档

1.1 什么是MySQL空间数据类型

MySQL空间数据类型是指MySQL数据库中支持的存储地理位置信息的数据类型,包括点、线、多边形等。这些数据类型可以用来存储地图坐标、地址信息等。
MySQL空间数据类型基于OpenGIS空间数据类型标准,提供了对空间数据进行索引和查询的功能,可以方便地实现地图应用、位置搜索等功能。

1.2 有哪些空间数据类型

  1. GEOMETRY:表示任意类型的几何对象,可以是点、线、面等,不受任何限制。
  2. POINT:表示一个点。
  3. LINESTRING:表示一条线。
  4. POLYGON:表示一个多边形。
  5. MULTIPOINT:表示多个点的集合。
  6. MULTILINESTRING:表示多条线的集合。
  7. MULTIPOLYGON:表示多个多边形的集合。
  8. GEOMETRYCOLLECTION:表示多个几何对象的集合。

空间数据类型之间存在继承关系、实例化和不可实例化,这些含义在后续的使用中体会下有什么区别。

1.3 支持空间数据类型的引擎

存储引擎 空间数据类型及其对应函数 空间索引 非空间索引
InnoDB Y Y Y
MyISAM Y Y Y
NDB Y N Y
ARCHIVE Y N Y

总而言之,若无其它特殊需求,用InnoDB就好。

1.4 坐标系类型

既然是存储空间数据,那么就有不同的规范和标准。比如说gps、gcj02等,同一个位置,它的经纬度坐标是不一样的。在创建空间索引列的时候,可以通过SRID显示制定空间索引的类型。

SRID是空间参考系统标识符(Spatial Reference System Identifier)的缩写,用于标识空间数据的坐标系。在不同的坐标系中,相同的坐标点可能有不同的坐标值。SRID的存在可以帮助我们正确地对空间数据进行分析和处理。常见的SRID标识符有EPSG、ESRI和SR-ORG等。

中国的坐标绘制是不同于GPS的,也可以理解成中国地图反馈给我们的坐标是gps坐标偏移之后的。由于存储系统是国外的MySQL,自身不支持国内的坐标系,除非寻找相关的插件。比如说微信小程序获取到的坐标是gcj02标准下、百度地图的坐标是bd09,我们可以通过hutool提供的坐标转换工具类进行转换,将不同标准下坐标统一转换成SRID为4326(GPS坐标)的坐标存储并计算。

hutool版本 5.8.10+ cn.hutool.core.util.CoordinateUtil

2. 存储坐标系的示例代码

2.1 geomtrypoint都可以存储坐标系,有什么区别呢?

GEOMETRY 是通用的几何类型,它可以存储点、线、面等多种类型的空间数据,且可以在不同的坐标系中表示空间数据。在声明空间索引列时,可以使用 GEOMETRY 类型,MySQL 会根据数据的实际类型自动选择对应的索引类型。

POINT 是 GEOMETRY 类型的一种特殊情况,它专门用于存储点类型的空间数据。在声明空间索引列时,如果确定该列只存储点类型的数据,可以使用 POINT 类型,这样可以提高索引的查询效率。

因此,使用 GEOMETRY 类型声明空间索引列可以存储多种类型的空间数据,但可能会降低索引的查询效率;使用 POINT 类型声明空间索引列只能存储点类型的数据,但可以提高索引的查询效率。

2.2 创建测试表

检查数据库是否支持SRID为4326的坐标系系统

SELECT *
FROM INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS
WHERE SRS_ID = 4326;

DDL

CREATE TABLE point_test ( 
  ID INT(11) unsigned not null auto_increment comment '主键', 
  address VARCHAR ( 64 ) NOT NULL comment '名称', 
  coordinate point NOT NULL SRID 4326 comment '位置坐标',
  primary key (ID),
  spatial index `spi_coordinate` (`coordinate`)
) ENGINE = INNODB charset = utf8;

2.3 新增坐标

工具一:gcj02坐标系在线拾取
工具二:gcj02wgs84坐标系在线转换

通过工具一获取到三个位置的gcj02坐标,然后通过工具二转换成wgs84(SRID=4326)坐标。分别是:

位置名称 gcj02 wgs84
上海虹桥机场 121.34,31.20 121.33543277248731,31.201919080690047
上海虹桥火车站 121.32,31.19 121.31547880904075,31.191962005342543
上海野生动物园 121.72,31.06 121.71564763519164,31.062121772948835
insert into point_test(
address, coordinate
) values
('上海虹桥机场', st_geomFromText('point(31.201919080690047 121.33543277248731)', 4326));

查询
MySQL 8.0.23 空间数据类型(Spatial Data Type)_第1张图片

新增时point()函数里的坐标是没有用逗号分隔的。

输入时的st_geomFromText(‘point({纬度} {经度})’, 4326),point()里的经纬度顺序变成了纬经度,查询时coordinate的POINT()确实经纬度,这是由于4326下的坐标系在新增时point的顺序是纬经度。可以通过下面的方式更换新增时的顺序。

insert into point_test(
address, coordinate
) values
('上海虹桥火车站', st_geomFromText('point(121.31547880904075 31.191962005342543)', 4326, 'axis-order=long-lat'));

MySQL 8.0.23 空间数据类型(Spatial Data Type)_第2张图片

st_geomFromText(...)可通过'axis-order=long-lat'来调整经纬度顺序。

把剩下一条也新增进来

insert into point_test(
address, coordinate
) values
('上海野生动物园', st_geomFromText('point(121.71564763519164 31.062121772948835)', 4326, 'axis-order=long-lat'));

2.3 计算两地之间的距离

官方函数列表:https://dev.mysql.com/doc/refman/8.0/en/built-in-function-reference.html

st_distance_sphere 返回值单位:米

select st_distance_sphere((select coordinate from point_test where id = 1), (select coordinate from point_test where id = 2)) 
as distance;

查询结果

2197.2655430832847

意思是虹桥机场距离虹桥火车站的球面距离约为2197米,即2.1公里。

这里的球面距离不代表行使总路程,毕竟甚少有路是点对点的,多少要走几个弯路。

执行计划显示查询性能较好
执行计划

2.5 列举距离我5km内的地址

有两种方式,一是通过st_distance_sphere计算距离,然后在where条件里面筛选,这样做是不走空间索引的,由于你给空间索引coordinate用了函数。
另一种方式是通过MBRContains函数,接下来重点介绍该函数。
假设我目前处于虹桥火车站,即我的坐标是121.31547880904075,31.191962005342543
步骤一:利用st_buffer(...)生成我的坐标为圆心,5000米为半径的圆形区域。


你可能感兴趣的:(#,1.MySQL,mysql,数据库,空间索引,距离)