第01章-PostGIS概述与入门
第01章:PostGIS 概述与入门
1.1 PostGIS 简介
1.1.1 什么是 PostGIS
PostGIS 是 PostgreSQL 数据库的一个开源空间扩展,它为 PostgreSQL 添加了对地理对象(Geographic Objects)的支持,使得 PostgreSQL 成为一个功能强大的空间数据库。PostGIS 遵循 OpenGIS 简单要素规范(Simple Features for SQL)和 ISO SQL/MM Spatial 标准,提供了丰富的空间数据类型、空间索引和数百个空间函数。
PostGIS 的名称来源于 "PostgreSQL + GIS",它将传统的关系型数据库管理系统与地理信息系统(GIS)的功能完美结合,为用户提供了在数据库层面处理空间数据的能力。
1.1.2 PostGIS 的核心特性
PostGIS 提供了以下核心特性:
-
空间数据类型
- Geometry(几何):适用于平面坐标系统
- Geography(地理):适用于球面坐标系统(经纬度)
- Raster(栅格):支持栅格数据存储和分析
-
空间索引
- GiST(Generalized Search Tree)索引:用于加速空间查询
- SP-GiST 索引:适用于特定的空间数据分布
- BRIN 索引:适用于大规模有序空间数据
-
空间函数
- 几何构造函数:创建点、线、面等几何对象
- 空间关系函数:判断几何对象之间的拓扑关系
- 空间分析函数:缓冲区分析、叠加分析、网络分析等
- 空间测量函数:计算距离、面积、长度等
-
标准支持
- OGC Simple Features for SQL
- ISO SQL/MM Spatial
- GeoJSON、GML、KML 等格式支持
-
高级功能
- 拓扑数据模型
- 三维几何支持
- 栅格数据处理
- 地理编码与路径规划
1.1.3 PostGIS 的历史发展
PostGIS 的发展历程可以追溯到 2001 年:
| 年份 | 版本 | 重要事件 |
|---|---|---|
| 2001 | 0.1 | PostGIS 项目启动,由 Refractions Research 开发 |
| 2004 | 0.9 | 支持 PostgreSQL 7.4,性能大幅提升 |
| 2006 | 1.0 | 首个稳定版本发布,功能趋于完善 |
| 2010 | 1.5 | 引入 Geography 类型,支持球面计算 |
| 2012 | 2.0 | 引入 Raster 支持,重大架构改进 |
| 2015 | 2.2 | 引入 BRIN 索引支持 |
| 2017 | 2.4 | 并行查询支持,性能优化 |
| 2019 | 3.0 | MVT(Mapbox Vector Tiles)原生支持 |
| 2021 | 3.1 | 改进的 3D 支持,更多函数 |
| 2022 | 3.2 | 性能优化,新增函数 |
| 2023 | 3.3 | 持续改进,新功能添加 |
| 2024 | 3.4 | 最新稳定版本 |
1.1.4 PostGIS 的优势
与其他空间数据库相比,PostGIS 具有以下优势:
1. 开源免费
- 完全开源,采用 GNU GPL v2 许可证
- 无需支付任何许可费用
- 活跃的社区支持
2. 功能强大
- 支持 1000+ 空间函数
- 完整的 OGC 标准支持
- 先进的空间索引技术
3. 性能卓越
- 高效的空间索引
- 支持并行查询
- 优化的空间算法
4. 生态丰富
- 与主流 GIS 软件无缝集成
- 丰富的编程语言驱动
- 活跃的第三方工具支持
5. 企业级特性
- 事务支持(ACID)
- 高可用性(复制、集群)
- 安全性和权限管理
6. 标准兼容
- OGC Simple Features for SQL
- ISO SQL/MM Spatial
- EPSG 坐标系统支持
1.2 PostGIS 应用场景
1.2.1 典型应用领域
PostGIS 广泛应用于以下领域:
1. 智慧城市
- 城市规划与管理
- 交通流量分析
- 公共设施选址
- 应急响应系统
2. 国土资源
- 土地利用管理
- 地籍管理
- 矿产资源管理
- 国土空间规划
3. 环境监测
- 水质监测
- 空气质量分析
- 生态环境评估
- 灾害预警系统
4. 交通物流
- 路线规划
- 车辆追踪
- 配送优化
- 交通流量分析
5. 电信行业
- 基站选址优化
- 网络覆盖分析
- 用户位置服务
- 信号质量评估
6. 农业林业
- 精准农业
- 林业资源管理
- 作物监测
- 病虫害预测
7. 公共安全
- 警务地理分析
- 消防资源调度
- 犯罪热点分析
- 应急资源管理
8. 商业智能
- 商业选址分析
- 客户分布分析
- 市场区域划分
- 竞争对手分析
1.2.2 技术架构示例
以下是一个典型的 PostGIS 应用架构:
┌─────────────────────────────────────────────────────────────┐
│ 前端应用层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Web GIS │ │ 移动应用 │ │ 桌面 GIS │ │ BI 工具 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
└───────┼─────────────┼─────────────┼─────────────┼──────────┘
│ │ │ │
┌───────┴─────────────┴─────────────┴─────────────┴──────────┐
│ 服务层 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 地图服务 │ │
│ │ GeoServer / MapServer / pg_tileserv / pg_featureserv │ │
│ └──────────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┴───────────────────────────┐ │
│ │ 应用服务 │ │
│ │ Spring Boot / Django / Flask / .NET Core / Node.js │ │
│ └──────────────────────────┬───────────────────────────┘ │
│ │ │
└─────────────────────────────┼───────────────────────────────┘
│
┌─────────────────────────────┴───────────────────────────────┐
│ 数据层 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ PostgreSQL + PostGIS │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 空间数据 │ │ 业务数据 │ │ 栅格数据 │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
1.2.3 实际案例
案例一:城市公共设施选址
某城市需要新建一个消防站,要求:
- 距离现有消防站至少 2 公里
- 能在 5 分钟内(按平均车速)覆盖尽可能多的居民区
- 距离主要道路不超过 500 米
-- 使用 PostGIS 进行消防站选址分析
WITH candidate_sites AS (
-- 找出距离现有消防站超过2公里的区域
SELECT ST_Difference(
(SELECT ST_Union(geom) FROM city_boundary),
(SELECT ST_Union(ST_Buffer(geom::geography, 2000)::geometry)
FROM fire_stations)
) AS available_area
),
road_buffer AS (
-- 主要道路500米缓冲区
SELECT ST_Union(ST_Buffer(geom::geography, 500)::geometry) AS buffer
FROM roads
WHERE road_type IN ('主干道', '次干道')
),
optimal_locations AS (
-- 找出满足条件的最佳位置
SELECT p.geom,
(SELECT COUNT(*) FROM residential_areas r
WHERE ST_DWithin(r.geom::geography, p.geom::geography, 3000)) AS coverage
FROM (
SELECT (ST_Dump(ST_Intersection(c.available_area, r.buffer))).geom
FROM candidate_sites c, road_buffer r
) p
)
SELECT geom, coverage
FROM optimal_locations
ORDER BY coverage DESC
LIMIT 5;
案例二:物流配送路线优化
-- 计算配送点之间的最短路径
SELECT * FROM pgr_dijkstra(
'SELECT id, source, target, length AS cost FROM road_network',
(SELECT id FROM delivery_points WHERE name = '配送中心'),
ARRAY(SELECT id FROM delivery_points WHERE type = '客户'),
directed := false
);
-- 计算每个配送点的服务区域
SELECT dp.name,
ST_Area(ST_Buffer(dp.geom::geography, 5000)) / 1000000 AS service_area_km2,
(SELECT COUNT(*) FROM customers c
WHERE ST_DWithin(c.geom::geography, dp.geom::geography, 5000)) AS customer_count
FROM delivery_points dp;
1.3 PostGIS 与其他技术的对比
1.3.1 与其他空间数据库对比
| 特性 | PostGIS | Oracle Spatial | SQL Server Spatial | MySQL Spatial |
|---|---|---|---|---|
| 开源性 | ✓ 完全开源 | ✗ 商业软件 | ✗ 商业软件 | ✓ 开源 |
| 空间函数数量 | 1000+ | 500+ | 200+ | 50+ |
| OGC 标准支持 | 完全 | 完全 | 部分 | 部分 |
| 栅格支持 | ✓ | ✓ | ✗ | ✗ |
| 拓扑支持 | ✓ | ✓ | ✗ | ✗ |
| 3D 支持 | ✓ | ✓ | 有限 | ✗ |
| Geography 类型 | ✓ | ✓ | ✓ | ✗ |
| 并行查询 | ✓ | ✓ | ✓ | 有限 |
| 社区活跃度 | 高 | 低 | 中 | 中 |
1.3.2 与文件格式对比
| 特性 | PostGIS | Shapefile | GeoPackage | GeoJSON |
|---|---|---|---|---|
| 多用户访问 | ✓ | ✗ | 有限 | ✗ |
| 事务支持 | ✓ | ✗ | ✓ | ✗ |
| 空间索引 | 高效 | 简单 | 中等 | 无 |
| 大数据量 | 优秀 | 差 | 中等 | 差 |
| SQL 查询 | ✓ | ✗ | ✓ | ✗ |
| 复杂分析 | ✓ | 需要工具 | 有限 | 需要工具 |
| 网络部署 | ✓ | 困难 | 困难 | ✓ |
1.3.3 与 NoSQL 空间数据库对比
| 特性 | PostGIS | MongoDB | Elasticsearch |
|---|---|---|---|
| 数据模型 | 关系型 | 文档型 | 文档型 |
| 空间索引 | GiST, BRIN | 2dsphere | BKD Tree |
| 空间函数 | 1000+ | 20+ | 10+ |
| 复杂分析 | 强 | 弱 | 弱 |
| SQL 支持 | ✓ | ✗ | ✗ |
| 事务支持 | 完整 | 有限 | ✗ |
| 适用场景 | 复杂GIS分析 | 简单位置查询 | 地理搜索 |
1.4 PostGIS 生态系统
1.4.1 核心组件
┌────────────────────────────────────────────────────────────┐
│ PostGIS 生态系统 │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 核心扩展 │ │
│ │ postgis - 核心几何功能 │ │
│ │ postgis_raster - 栅格数据支持 │ │
│ │ postgis_topology - 拓扑数据模型 │ │
│ │ postgis_sfcgal - 高级3D/CGAL功能 │ │
│ │ postgis_tiger_geocoder - 美国地址地理编码 │ │
│ │ address_standardizer - 地址标准化 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 依赖库 │ │
│ │ GEOS - 几何引擎(空间操作) │ │
│ │ PROJ - 坐标参考系统转换 │ │
│ │ GDAL - 栅格数据处理 │ │
│ │ LibXML2 - XML解析 │ │
│ │ JSON-C - JSON处理 │ │
│ │ SFCGAL - 高级3D功能 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
1.4.2 相关工具
数据管理工具
- pgAdmin:PostgreSQL 官方管理工具
- DBeaver:通用数据库管理工具
- QGIS DB Manager:QGIS 内置数据库管理器
- shp2pgsql:Shapefile 导入工具
- raster2pgsql:栅格数据导入工具
- ogr2ogr:GDAL 数据转换工具
地图服务工具
- GeoServer:开源地图服务器
- MapServer:开源地图服务器
- pg_tileserv:矢量瓦片服务
- pg_featureserv:要素服务
可视化工具
- QGIS:开源桌面 GIS
- OpenJUMP:开源 GIS 工具
- uDig:用户友好的桌面 GIS
开发框架
- GeoAlchemy2:Python SQLAlchemy 空间扩展
- GeoDjango:Django 地理框架
- JTS:Java 拓扑套件
- NetTopologySuite:.NET 空间库
1.4.3 集成生态
┌────────────────────────────────────────────────────────────┐
│ 集成生态 │
├────────────────────────────────────────────────────────────┤
│ │
│ 前端框架 │
│ ├── OpenLayers │
│ ├── Leaflet │
│ ├── Mapbox GL JS │
│ ├── Cesium │
│ └── deck.gl │
│ │
│ 后端框架 │
│ ├── Spring Boot + JPA │
│ ├── Django + GeoDjango │
│ ├── Flask + GeoAlchemy2 │
│ ├── .NET Core + NetTopologySuite │
│ └── Node.js + node-postgres │
│ │
│ ETL 工具 │
│ ├── FME │
│ ├── GeoKettle │
│ ├── GDAL/OGR │
│ └── Apache NiFi │
│ │
│ BI 工具 │
│ ├── Tableau │
│ ├── Power BI │
│ ├── Apache Superset │
│ └── Metabase │
│ │
└────────────────────────────────────────────────────────────┘
1.5 PostGIS 架构详解
1.5.1 整体架构
PostGIS 作为 PostgreSQL 的扩展,其架构可以从以下几个层面理解:
┌─────────────────────────────────────────────────────────────┐
│ 应用层 │
│ SQL 查询、存储过程、触发器 │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ PostGIS 扩展层 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ SQL/MM 函数 │ │
│ │ ST_Buffer, ST_Intersection, ST_Union, ... │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 空间数据类型 │ │
│ │ geometry, geography, raster, topology │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 空间索引 │ │
│ │ GiST Index, SP-GiST Index, BRIN Index │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ PostgreSQL 核心 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 存储引擎 │ 查询优化器 │ 事务管理 │ 并发控制 │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ 底层依赖库 │
│ GEOS │ PROJ │ GDAL │ SFCGAL │
│ (几何) (投影) (栅格) (3D) │
└─────────────────────────────────────────────────────────────┘
1.5.2 数据存储
PostGIS 的空间数据存储采用了高效的二进制格式:
EWKB(Extended Well-Known Binary)
PostGIS 使用 EWKB 格式在数据库中存储几何数据,这是 OGC WKB 格式的扩展版本:
┌─────────────────────────────────────────────────────────────┐
│ EWKB 格式结构 │
├─────────────────────────────────────────────────────────────┤
│ 字节顺序 (1字节) │
│ └─ 0x01: 小端序 │
│ └─ 0x00: 大端序 │
├─────────────────────────────────────────────────────────────┤
│ 几何类型 (4字节) │
│ └─ 类型标识 │
│ └─ SRID 标志位 │
│ └─ Z/M 标志位 │
├─────────────────────────────────────────────────────────────┤
│ SRID (4字节, 可选) │
│ └─ 空间参考系统标识符 │
├─────────────────────────────────────────────────────────────┤
│ 几何数据 │
│ └─ 坐标数据 │
│ └─ 子几何数据(复合几何) │
└─────────────────────────────────────────────────────────────┘
1.5.3 空间索引原理
GiST 索引(通用搜索树)
GiST(Generalized Search Tree)是 PostGIS 默认的空间索引类型,它使用 R-Tree 的变体来组织空间数据:
┌─────────────────────────────────────────────────────────────┐
│ GiST R-Tree 结构 │
│ │
│ ┌─────┐ │
│ │ 根 │ │
│ └──┬──┘ │
│ ┌──────┴──────┐ │
│ │ │ │
│ ┌──┴──┐ ┌──┴──┐ │
│ │ MBR │ │ MBR │ │
│ └──┬──┘ └──┬──┘ │
│ ┌─────┼─────┐ │ │
│ │ │ │ │ │
│ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌──┴──┐ │
│ │obj│ │obj│ │obj│ │ obj │ │
│ └───┘ └───┘ └───┘ └─────┘ │
│ │
│ MBR = Minimum Bounding Rectangle (最小外接矩形) │
└─────────────────────────────────────────────────────────────┘
创建空间索引:
-- 创建 GiST 空间索引
CREATE INDEX idx_geom ON my_table USING GIST (geom);
-- 创建包含 SRID 的索引
CREATE INDEX idx_geom_srid ON my_table USING GIST (geom)
WHERE ST_SRID(geom) = 4326;
1.6 入门准备
1.6.1 学习路径建议
对于 PostGIS 初学者,建议按以下路径学习:
第一阶段:基础入门(1-2周)
- 了解 PostGIS 基本概念
- 安装 PostgreSQL 和 PostGIS
- 学习基本的空间数据类型
- 掌握简单的空间查询
第二阶段:深入学习(2-4周)
- 学习常用空间函数
- 理解空间参考系统
- 掌握空间索引使用
- 练习数据导入导出
第三阶段:高级应用(4-8周)
- 学习复杂空间分析
- 了解性能优化技术
- 学习栅格数据处理
- 掌握拓扑功能
第四阶段:实战项目(持续)
- 实际项目开发
- 与其他系统集成
- 深入性能调优
- 参与社区贡献
1.6.2 学习资源
官方资源
- PostGIS 官方文档:https://postgis.net/documentation/
- PostgreSQL 官方文档:https://www.postgresql.org/docs/
- PostGIS Workshop:https://postgis.net/workshops/
推荐书籍
- 《PostGIS in Action》(第三版)
- 《PostgreSQL: Up and Running》
- 《Mastering PostGIS》
在线教程
- PostGIS 官方教程
- Boundless 教程(现为 Planet)
- OSGeo Live 示例数据集
社区资源
- PostGIS 邮件列表
- Stack Overflow (postgis 标签)
- GIS Stack Exchange
1.6.3 实验环境
推荐的实验环境配置:
最小配置
- CPU:2 核
- 内存:4GB
- 存储:20GB SSD
- 系统:Ubuntu 22.04 LTS
推荐配置
- CPU:4 核以上
- 内存:8GB 以上
- 存储:50GB SSD
- 系统:Ubuntu 22.04 LTS 或 Windows 11
Docker 环境
# docker-compose.yml
version: '3.8'
services:
postgis:
image: postgis/postgis:16-3.4
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: gis_tutorial
ports:
- "5432:5432"
volumes:
- postgis_data:/var/lib/postgresql/data
volumes:
postgis_data:
1.7 第一个 PostGIS 查询
让我们通过一个简单的示例来体验 PostGIS 的强大功能:
1.7.1 创建空间表
-- 创建扩展
CREATE EXTENSION IF NOT EXISTS postgis;
-- 创建城市表
CREATE TABLE cities (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
population INTEGER,
geom GEOMETRY(POINT, 4326)
);
-- 创建空间索引
CREATE INDEX idx_cities_geom ON cities USING GIST (geom);
1.7.2 插入数据
-- 插入中国主要城市数据
INSERT INTO cities (name, population, geom) VALUES
('北京', 21540000, ST_SetSRID(ST_MakePoint(116.4074, 39.9042), 4326)),
('上海', 24870000, ST_SetSRID(ST_MakePoint(121.4737, 31.2304), 4326)),
('广州', 15300000, ST_SetSRID(ST_MakePoint(113.2644, 23.1291), 4326)),
('深圳', 17560000, ST_SetSRID(ST_MakePoint(114.0579, 22.5431), 4326)),
('成都', 16330000, ST_SetSRID(ST_MakePoint(104.0665, 30.5723), 4326)),
('杭州', 12200000, ST_SetSRID(ST_MakePoint(120.1551, 30.2741), 4326)),
('武汉', 12320000, ST_SetSRID(ST_MakePoint(114.3054, 30.5931), 4326)),
('西安', 12950000, ST_SetSRID(ST_MakePoint(108.9402, 34.3416), 4326)),
('南京', 9420000, ST_SetSRID(ST_MakePoint(118.7969, 32.0603), 4326)),
('重庆', 32050000, ST_SetSRID(ST_MakePoint(106.5516, 29.5630), 4326));
1.7.3 空间查询
-- 查询距离北京最近的5个城市
SELECT
name,
population,
ROUND(ST_Distance(
geom::geography,
(SELECT geom FROM cities WHERE name = '北京')::geography
) / 1000) AS distance_km
FROM cities
WHERE name != '北京'
ORDER BY geom::geography <->
(SELECT geom FROM cities WHERE name = '北京')::geography
LIMIT 5;
-- 结果示例:
-- name | population | distance_km
-- ------+------------+-------------
-- 西安 | 12950000 | 912
-- 南京 | 9420000 | 900
-- 武汉 | 12320000 | 1052
-- 杭州 | 12200000 | 1133
-- 上海 | 24870000 | 1068
1.7.4 空间分析
-- 查询人口超过1500万且相互距离在1000公里以内的城市对
WITH big_cities AS (
SELECT name, population, geom
FROM cities
WHERE population > 15000000
)
SELECT
a.name AS city1,
b.name AS city2,
ROUND(ST_Distance(a.geom::geography, b.geom::geography) / 1000) AS distance_km
FROM big_cities a, big_cities b
WHERE a.name < b.name
AND ST_DWithin(a.geom::geography, b.geom::geography, 1000000)
ORDER BY distance_km;
-- 计算所有城市的中心点
SELECT ST_AsText(ST_Centroid(ST_Collect(geom))) AS center
FROM cities;
-- 创建包含所有城市的最小外接矩形
SELECT ST_AsText(ST_Envelope(ST_Collect(geom))) AS bounding_box
FROM cities;
1.8 本章小结
本章介绍了 PostGIS 的基本概念和特性:
- PostGIS 简介:了解了 PostGIS 作为 PostgreSQL 空间扩展的核心功能和特点
- 历史发展:回顾了 PostGIS 从 2001 年至今的发展历程
- 应用场景:探讨了 PostGIS 在智慧城市、交通物流等领域的应用
- 技术对比:比较了 PostGIS 与其他空间数据库的优劣
- 生态系统:介绍了 PostGIS 相关的工具和集成方案
- 架构详解:深入了解了 PostGIS 的技术架构
- 入门准备:提供了学习路径和环境配置建议
- 第一个查询:通过实例体验了 PostGIS 的基本功能
1.9 下一步
在下一章中,我们将学习 PostGIS 的安装与环境配置,包括:
- Windows 环境安装配置
- Linux 环境安装配置
- Docker 部署方案
- 常见问题排查
- 开发环境配置
相关资源:

浙公网安备 33010602011771号