MySQL空间数据类型官方文档
MySQL空间数据类型是指MySQL数据库中支持的存储地理位置信息的数据类型,包括点、线、多边形等。这些数据类型可以用来存储地图坐标、地址信息等。
MySQL空间数据类型基于OpenGIS空间数据类型标准,提供了对空间数据进行索引和查询的功能,可以方便地实现地图应用、位置搜索等功能。
空间数据类型之间存在继承关系、实例化和不可实例化,这些含义在后续的使用中体会下有什么区别。
存储引擎 | 空间数据类型及其对应函数 | 空间索引 | 非空间索引 |
---|---|---|---|
InnoDB | Y | Y | Y |
MyISAM | Y | Y | Y |
NDB | Y | N | Y |
ARCHIVE | Y | N | Y |
总而言之,若无其它特殊需求,用InnoDB就好。
既然是存储空间数据,那么就有不同的规范和标准。比如说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
geomtry
和point
都可以存储坐标系,有什么区别呢?GEOMETRY 是通用的几何类型,它可以存储点、线、面等多种类型的空间数据,且可以在不同的坐标系中表示空间数据。在声明空间索引列时,可以使用 GEOMETRY 类型,MySQL 会根据数据的实际类型自动选择对应的索引类型。
POINT 是 GEOMETRY 类型的一种特殊情况,它专门用于存储点类型的空间数据。在声明空间索引列时,如果确定该列只存储点类型的数据,可以使用 POINT 类型,这样可以提高索引的查询效率。
因此,使用 GEOMETRY 类型声明空间索引列可以存储多种类型的空间数据,但可能会降低索引的查询效率;使用 POINT 类型声明空间索引列只能存储点类型的数据,但可以提高索引的查询效率。
检查数据库是否支持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;
工具一:gcj02
坐标系在线拾取
工具二:gcj02
与wgs84
坐标系在线转换
通过工具一获取到三个位置的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));
新增时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'));
在
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'));
官方函数列表: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公里。
这里的球面距离不代表行使总路程,毕竟甚少有路是点对点的,多少要走几个弯路。
有两种方式,一是通过st_distance_sphere
计算距离,然后在where条件里面筛选,这样做是不走空间索引的,由于你给空间索引coordinate用了函数。
另一种方式是通过MBRContains
函数,接下来重点介绍该函数。
假设我目前处于虹桥火车站
,即我的坐标是121.31547880904075,31.191962005342543
。
步骤一:利用st_buffer(...)
生成我的坐标为圆心,5000米为半径的圆形区域。