📌今日关键词:空间数据库、PostGIS、GIS、空间索引、R-Tree、融合数据库
大家好,我是数据库小学妹 👋
做过外卖系统的同学应该都有体会:骑手位置、商户坐标、配送范围,全是空间数据。存起来容易,查起来要命——"3公里内的骑手"这个查询,数据量一大就卡得不行。
问题出在哪?大概率出在数据库选型上。
空间数据不像普通业务数据,它有坐标系、有几何运算、有拓扑关系。选错了数据库,索引效率差、SQL写不出、性能上不去。
目前主流的空间数据存储方案有三个流派:PostGIS、MySQL空间扩展、国产融合数据库。今天把它们的核心差异拆开讲清楚。
一、先搞懂空间数据长什么样
空间数据主要分两类:
矢量数据: 用坐标点描述几何形状
- POINT(点):一个经纬度坐标,比如骑手当前位置
- LINESTRING(线):一串坐标点连成的线,比如道路、河流
- POLYGON(多边形):围成封闭区域,比如配送范围、行政区划
栅格数据: 像素网格,比如卫星影像、DEM高程数据。这个一般用专门的栅格引擎,不在本文讨论范围。
空间数据的核心操作:
- 空间关系判断: A是否在B范围内?(ST_Within)A和B是否相交?(ST_Intersects)
- 距离计算: A到B的直线距离是多少?(ST_Distance)
- 缓冲区分析: 以某点为中心画3公里圆,找出范围内所有目标(ST_Buffer)
- 空间聚合: 某区域内有多少个点?
这些操作的性能,取决于数据库的空间索引能力。
二、三大方案核心对比
2.1 PostGIS
PostGIS是PostgreSQL的空间扩展插件,是GIS领域的老牌选手。
优势:
- 空间函数丰富,800多个空间函数,覆盖OGC标准
- GiST索引成熟,空间查询性能好
- 支持坐标系转换(PROJ库),全球各种坐标系都能处理
- 社区活跃,文档齐全,遇到问题容易找到解决方案
- 支持栅格数据(PostGIS Raster)
不足:
- 需要单独维护一套PostgreSQL实例
- 空间数据和业务数据分库存储,联合查询要跨库
- 高并发写入场景下性能有瓶颈
- 国产化替代时,需要额外评估合规性
适合场景: GIS专业应用、地理信息系统、需要复杂空间分析的场景
2.2 MySQL空间扩展
MySQL内置了空间数据类型和空间索引,开箱即用。
优势:
- 不需要额外插件,建表时指定空间列就行
- SPATIAL INDEX基于R-Tree,基本的空间查询能用
- 业务数据和空间数据同库,减少架构复杂度
- 运维团队大多熟悉MySQL,学习成本低
不足:
- 空间函数比PostGIS少很多
- 坐标系支持有限,自定义坐标系比较麻烦
- 空间索引在复杂多边形查询下效率一般
- 对三维坐标(Z值)支持不完善
- GIS专业功能不足,不适合重度GIS场景
适合场景: 业务系统中附带空间功能(LBS、外卖、打车),空间分析需求不复杂
2.3 国产融合数据库(以KES为例)
国产数据库在空间能力上正在快速追赶。KES V9走的是融合架构路线:把空间能力直接内置到数据库引擎里。
优势:
- 空间数据、关系数据、时序数据在同一个库里
- 一条SQL就能关联空间表和业务表,不用跨库
- 符合信创要求,国产化合规无忧
- 运维一套系统,不用分别维护GIS库和业务库
- 2025年KES与超图软件达成战略合作,空间能力持续增强
不足:
- 社区生态比PostGIS小
- 复杂GIS分析场景可能需要配合专业GIS软件
适合场景: 信创场景、需要空间数据和业务数据融合分析、不想维护多套系统
三、空间索引,性能差异的核心
空间查询的性能好不好,七成取决于索引。
3.1 R-Tree索引
R-Tree是空间索引的主流算法。它把空间对象用最小外接矩形(MBR)逐层聚合,形成树状结构。
PostGIS用GiST索引实现R-Tree,MySQL用SPATIAL INDEX,KES用空间索引。底层都是R-Tree变种,但实现细节和优化程度不同。
3.2 索引效率对比
实际测试场景:1000万个点要素,查询"某矩形范围内有多少个点":
| 方案 | 索引类型 | 查询耗时(参考值) |
|---|---|---|
| PostGIS | GiST | 50-100ms |
| MySQL | SPATIAL INDEX | 100-200ms |
| KES | GiST、BRIN和SP-GiST三种空间索引 | 80-150ms |
数据量越大,索引效率的差距越明显。百万级以下差别不大,千万级以上开始拉开差距。
3.3 空间SQL写法对比
-- 查找某点3公里范围内的所有商户
-- PostGIS
SELECT name, ST_Distance(
geom::geography,
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography
) AS dist
FROM shops
WHERE ST_DWithin(
geom::geography,
ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography,
3000
)
ORDER BY dist;
-- MySQL
SELECT name, ST_Distance_Sphere(
location,
ST_GeomFromText('POINT(116.40 39.90)', 4326)
) AS dist
FROM shops
WHERE ST_Distance_Sphere(
location,
ST_GeomFromText('POINT(116.40 39.90)', 4326)
) <= 3000
ORDER BY dist;
-- KES(SQL写法与PostGIS类似)
SELECT name, ST_Distance(geom, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)) AS dist
FROM shops
WHERE ST_DWithin(geom, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326), 3000)
ORDER BY dist;
从SQL写法看,PostGIS和KES更接近OGC标准,MySQL的写法有自己的风格。
四、坐标系,容易踩的大坑
国内空间数据有两个常见坐标系:
- WGS-84: GPS原始坐标,国际标准
- GCJ-02: 国测局坐标,高德、腾讯地图用这个
- BD-09: 百度坐标,在GCJ-02基础上再加偏移
不同数据库对坐标系的支持差异:
- PostGIS支持完整的SRID定义和坐标转换(PROJ库),可以自由转换WGS-84和GCJ-02
- MySQL的坐标系支持较弱,自定义坐标系比较麻烦
- KES支持坐标系定义和常见转换
重点提醒: 迁移空间数据前,先确认源数据的坐标系。不同坐标系混在一起查,结果会差几百米到几公里。
五、怎么选?一张决策表帮你搞定
| 决策维度 | PostGIS | MySQL | KES融合库 |
|---|---|---|---|
| 空间函数丰富度 | 高(800+) | 中(基础函数) | 中高 |
| 空间索引性能 | 优秀 | 良好 | 良好 |
| 坐标系支持 | 完整 | 有限 | 良好 |
| 业务数据联合查询 | 需跨库 | 同库 | 同库 |
| 信创合规 | 需评估 | 需评估 | 原生支持 |
| 运维复杂度 | 中(单独维护) | 低 | 低(融合架构) |
| 学习成本 | 中 | 低 | 低 |
| 社区生态 | 丰富 | 丰富 | 成长中 |
选型建议:
- 重度GIS分析: 选PostGIS。空间函数全,社区成熟。
- 轻量LBS应用: MySQL够用。空间查询不复杂,业务数据为主,同库维护省心。
- 信创场景或空间+业务融合分析: 选KES融合库。空间数据和业务数据在同一个库里,一条SQL关联查询,不用折腾ETL。
- 已有国产数据库规划: 直接用KES的空间能力,不额外部署GIS数据库。
六、实战建议
6.1 数据量预估
- 100万条以下:三个方案性能差异不大,按运维便利性选
- 100万-1000万:关注索引类型和查询优化
- 1000万以上:必须做基准测试,索引效率差异明显
6.2 迁移注意事项
- PostGIS到KES:空间函数名称大部分兼容,注意ST_Transform等坐标系函数
- MySQL到KES:空间函数写法差异较大,ST_Distance_Sphere需要改写
- 坐标系迁移:保留原始SRID定义,迁移后验证坐标偏移
6.3 性能优化
- 空间索引一定要建。没有空间索引的空间查询,性能差100倍以上
- 大表空间JOIN,先做空间裁剪(bounding box过滤),再做精确计算
- 避免对几何列做函数计算后再过滤,会导致索引失效
小结
空间数据库选型得看具体场景。空间分析是主角还是配角?数据量级多大?需不需要和业务数据融合查询?有没有信创合规要求?
这几个问题想清楚,方案自然就明确了。
大家在空间数据存储上踩过哪些坑?用的什么方案?评论区分享一下 👇
我是数据库小学妹,咱们下篇见 👋