2.1 空间数据库 (Spatial Database)


2.1 空间数据库 (Spatial Database)

本节摘要:空间数据有几何有属性,普通数据库存不好。本节讲空间数据库(以 PostGIS 为代表)怎么存空间数据、空间函数怎么用。

先说结论

阅读完本节,你应当能够:

  1. 理解空间数据库的特点
  2. 用 PostGIS 存和查空间数据
  3. 用空间函数做基本分析

概念脉络

一、为什么需要空间数据库

普通数据库存不了几何,查询"我附近 1km 的餐厅"要算距离,普通 SQL 做不到。空间数据库扩展了几何类型、空间函数、空间索引,能用 SQL 做空间查询和分析。

主流空间数据库:

  • PostGIS(PostgreSQL 扩展):最成熟,开源首选
  • Oracle Spatial:商业,企业级
  • SQL Server Spatial:微软生态
  • MySQL Spatial:轻量,功能较少
  • SpatiaLite:SQLite 扩展,移动端

二、PostGIS 基础

图 2-1 空间数据库架构

图 2-1 空间数据库架构

-- 启用 PostGIS CREATE EXTENSION postgis; -- 建表存空间数据 CREATE TABLE restaurants ( id SERIAL PRIMARY KEY, name VARCHAR(100), geom GEOMETRY(POINT, 4326) ); -- 插入 INSERT INTO restaurants (name, geom) VALUES ('餐厅A', ST_SetSRID(ST_Point(116.4, 39.9), 4326));

三、几何类型

  • GEOMETRY:平面坐标,用投影坐标系,计算快
  • GEOGRAPHY:球面坐标,用经纬度,算大圆距离准确但慢

小范围用 GEOMETRY + 投影坐标系,全球范围算距离用 GEOGRAPHY。

四、空间函数

PostGIS 提供大量 ST_ 开头的空间函数:

-- 距离 SELECT ST_Distance(a.geom, b.geom) FROM ...; -- 包含 SELECT * FROM cities WHERE ST_Within(geom, (SELECT geom FROM region WHERE name='北京')); -- 相交 SELECT * FROM roads WHERE ST_Intersects(geom, flood_area); -- 缓冲区 SELECT ST_Buffer(geom, 1000); -- 1km 缓冲 -- 面积/长度 SELECT ST_Area(geom), ST_Length(geom) FROM ...;

五、空间查询示例

"找某点 1km 内的餐厅":

SELECT name, ST_Distance(geom, my_point) AS dist FROM restaurants WHERE ST_DWithin(geom, my_point, 1000) -- 1km 内 ORDER BY dist;

ST_DWithin 配合空间索引能快速过滤,不用逐个算距离。

⚠️ 常见坑:用 GEOMETRY 存经纬度算距离——平面坐标算的是直线距离不是球面距离,长距离误差大。算球面距离用 GEOGRAPHY 或 ST_DistanceSphere。

💡 关键直觉:空间数据库扩展了几何类型+空间函数+空间索引。PostGIS 是首选,用 ST_ 函数做空间查询,ST_DWithin 配索引快速过滤。

六、PostGIS 安装与版本

PostGIS 是 PostgreSQL 的扩展,安装分两步:先在系统里安装扩展包,再在目标数据库里启用:

# Ubuntu 安装(各系统命令不同,装最新稳定版即可) sudo apt install postgresql postgis postgresql-14-postgis-3
-- 在目标数据库启用扩展 CREATE EXTENSION postgis; -- 验证安装成功 SELECT PostGIS_Version();

版本匹配值得注意:PostGIS 3.x 默认使用 GEOS 3.9+,空间函数性能和精度都有提升;如果你的老项目还在用 PostGIS 2.x,升级后部分函数签名不变,但 ST_MakeValid 等函数的行为更严格。日常开发建议跟随发行版的稳定版本,不必追最新。

七、常用空间函数分组

PostGIS 的 ST_ 函数按用途分几组,掌握每组代表函数就能覆盖绝大多数场景:

分组 代表函数 用途
构造 ST_Point、ST_GeomFromText、ST_MakePolygon 从坐标或文本构造几何
转换 ST_Transform、ST_SetSRID、ST_AsGeoJSON 坐标系转换、格式导出
关系 ST_Intersects、ST_Contains、ST_DWithin 空间关系判断
计算 ST_Distance、ST_Area、ST_Length、ST_Buffer 距离面积缓冲
分析 ST_Union、ST_Intersection、ST_Simplify 叠加、合并、简化
栅格 ST_Value、ST_Clip、ST_Resample 栅格取值、裁剪、重采样

八、一个完整案例:商圈热度分析

需求:某零售公司要评估每个商圈 3 公里内有多少家门店。数据是门店表(含 point 几何)和商圈表(含 polygon 几何)。一条 SQL 完成:

SELECT b.name AS 商圈, count(s.id) AS 门店数, round(avg(ST_Distance(s.geom::geography, b.geom::geography))) AS 平均距离米 FROM districts b LEFT JOIN stores s ON ST_DWithin(s.geom::geography, b.geom::geography, 3000) WHERE b.type = '商圈' GROUP BY b.id, b.name;

注意这里把 geometry 转成 geography 做球面距离判断,3 公里范围内结果比平面计算更符合真实道路距离的预期。数据量大时,给 stores 表的 geom 建 GiST 索引,查询从几秒降到几十毫秒。

九、空间数据库选型对比

数据库 空间支持 适合场景 局限
PostgreSQL + PostGIS 最全 中大型 GIS 系统 需要单独部署
MySQL Spatial 基础函数 轻量 Web 项目 函数少、分析弱
SQL Server Spatial 较全 微软技术栈企业 商业授权
Oracle Spatial 很全 大型政企 贵、重
SQLite + Spatialite 基础 移动端离线 并发弱

选型建议:新项目无特殊约束一律 PostGIS;已有 MySQL 的轻量项目可用 MySQL 的空间函数做简单查询,复杂分析还是交给 PostGIS。

十、性能经验补充

空间数据库的查询性能,除了索引还受几个因素影响,这里补充几条经验:

  • 查询裁剪:先按空间范围缩小数据再计算。SQL 里先 WHERE ST_Intersects(geom, 查询范围) 粗筛,再对少量结果做精确计算,比直接对大表算快得多。
  • 避免函数包裹索引列WHERE ST_Length(geom) > 10 这类写法无法利用索引;把长度预先存成普通字段并建 B 树索引。
  • 批量写入用 COPY:导入几十万条记录时用 PostgreSQL 的 COPY 或 shp2pgsql 批量模式,比逐条 INSERT 快一个数量级,导入前可以先删索引。
-- 批量导入示例(shp2pgsql 管道导入) shp2pgsql -s 4490 -D parcels.shp parcels | psql -d gis_test -- -D 表示用 COPY 模式,速度快

重点提炼

  • 空间数据库:扩展几何类型/空间函数/空间索引,能用 SQL 做空间分析。
  • 主流:PostGIS(首选)、Oracle Spatial、SQL Server Spatial、MySQL Spatial。
  • PostGISCREATE EXTENSION postgis,GEOMETRY 类型存几何。
  • 几何类型:GEOMETRY(平面快)、GEOGRAPHY(球面准)。
  • 空间函数ST_Distance/ST_Within/ST_Intersects/ST_Buffer/ST_Area
  • 查询ST_DWithin 配索引快速过滤附近要素。

下一节讲空间索引——怎么让空间查询快起来。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U