标签:MySQL、数据库、空间数据、冷门数据类型
前言
平时开发业务系统,大家打交道最多的就是INT、VARCHAR、DECIMAL、DATETIME这些类型。很多人写了好几年SQL,甚至不知道MySQL还内置了一套空间数据类型。
空间类型里,POINT还算偶尔有人听过,但GEOMETRY作为所有空间类型的父类,就属于典型的不常用但很有意思的数据类型。今天就专门讲讲它。
什么是 GEOMETRY?
MySQL从5.6版本开始完善空间数据支持,8.0做了大量优化。GEOMETRY是一个通用几何类型,它可以存放任意一种空间几何对象:
- 点 POINT
- 线 LINESTRING
- 多边形 POLYGON
- 多点 MULTIPOINT
- 多线 MULTILINESTRING
- 多多边形 MULTIPOLYGON
- 几何集合 GEOMETRYCOLLECTION
简单一句话:POINT只能存坐标点;而GEOMETRY字段,同一个表里的不同行,可以一会儿存点、一会儿存线、一会儿存多边形。
这就是它和其他空间类型最大的区别。
适用场景一句话总结:当一行数据不确定是点/线/面,多种几何图形混存的时候,才选 GEOMETRY。
基础建表 & 写入示例
创建一张包含GEOMETRY字段的表:
CREATETABLEgeo_test(idINTPRIMARYKEYAUTO_INCREMENT,nameVARCHAR(100),geo_dataGEOMETRYNOTNULL,-- 可选,创建空间索引(空间查询必备)SPATIALINDEXidx_geo(geo_data));插入一条点数据:
INSERTINTOgeo_test(name,geo_data)VALUES('重庆某点位',ST_GeomFromText('POINT(106.55 29.56)'));再插入一个多边形(区域),同一张表同一个字段,直接换类型:
INSERTINTOgeo_test(name,geo_data)VALUES('某区域多边形',ST_GeomFromText('POLYGON((106 29,107 29,107 30,106 30,106 29))'));查询 GEOMETRY 字段
直接SELECT拿到的是二进制存储格式,人看不懂,要用ST_AsText()转成可读WKT文本:
SELECTid,name,ST_AsText(geo_data)FROMgeo_test;判断类型:用ST_GeometryType(),就能看出当前这条记录存的是点还是多边形
SELECTid,name,ST_GeometryType(geo_data)ASgeom_type,ST_AsText(geo_data)ASwktFROMgeo_test;常用空间函数举例:
ST_Contains(a,b):判断几何A是否包含B(常用于判断坐标是否落在区域内)ST_Distance():计算两个几何对象之间的距离ST_GeomFromText():WKT文本转为GEOMETRY二进制ST_AsText():二进制转回WKT可读文本
什么时候该用 GEOMETRY?什么时候别用?
✅ 适合场景
- 一套表里面,同时存储点、线段、多边形多种地理图形,类型不固定。比如地图后台,既存点位标记,又存围栏区域。
- 通用空间数据存储,统一入库,上层业务再判断几何类型做不同渲染。
❌ 不推荐场景(绝大多数业务)
- 只存经纬度坐标点:直接用
POINT,性能更好,约束更强,不应该上GEOMETRY。 - 高并发、超大表:空间索引开销不小,很多业务会把地理计算交给Redis/GIS服务(PostGIS、高德/百度地图API),不在MySQL里做复杂空间运算。
- 简单业务后台,没有地图需求:完全没必要引入,增加团队理解成本。
容易踩的坑
- 旧版本MySQL坑:5.6之前空间类型支持很差,不要在老版本线上库随便玩。推荐MySQL8.0。
- SPATIAL索引限制:如果字段允许NULL,部分版本空间索引会有问题;且只有GEOMETRY、POINT这类空间类型支持空间索引,普通字段不行。
- 坐标系问题:默认是笛卡尔平面坐标,不是地理球面坐标!
如果要做真实地球经纬度距离计算,需要指定SRID(8.0支持SRID,推荐SRID=4326,也就是WGS84,GPS通用坐标系)。-- 带SRID的写法ST_GeomFromText('POINT(106.55 29.56)',4326) - 不要拿GEOMETRY替代VARCHAR存WKT字符串!
很多新手图省事直接把WKT文本放进VARCHAR,就失去了空间索引、空间函数能力;反过来,如果你不需要空间计算,单纯存文本,也没必要用GEOMETRY。
和 POINT 的直观对比
| 类型 | 可存储几何对象 | 使用场景 |
|---|---|---|
| POINT | 仅坐标点 | 经纬度点位,最常用的空间类型 |
| GEOMETRY | 点、线、多边形、几何集合全部支持 | 多种几何类型混存,通用GIS数据 |
写在最后
GEOMETRY在普通业务开发里确实属于冷门选手。绝大多数项目,存经纬度用POINT,甚至直接两个DECIMAL字段分开存lng/lat就够用。
但如果你做地图后台、电子围栏、地理信息相关系统,它就有发挥空间。不过实际生产中,很多GIS项目会单独使用PostgreSQL+PostGIS,而不是重度依赖MySQL的空间能力。
简单总结:知道有这个东西,看懂它能干啥;不到多种几何混存的场景,尽量不用。