
简介PostGIS 3.3.6 源码安装包面向需要在 PostgreSQL 上构建空间数据库能力的开发者与 GIS 工程师用于存储、检索、分析地理空间数据适用于城市规划、环境监测、交通物流等场景。压缩包共约 2000 个文件整体 16.98MB以 457 个 sql 脚本、269 个 c 源码、127 个 h 头文件、418 个 po 本地化文件为主另含 wkt、expected 测试用例、shp/dbf/shx 示例数据及 png、xml 等资源覆盖核心扩展、拓扑与栅格模块。已有 69 人学习下载。包内提供完整源码与回归测试用例可帮助读者理解空间数据类型、空间索引、空间函数与坐标参考系统转换的实现方式并支持自行编译安装、按需定制扩展功能是研究开源空间数据库内部机制的实用参考。1. 从源码包到空间数据库postgis-3.3.6.tar.gz 到底解决什么问题很多人第一次拿到postgis-3.3.6.tar.gz这种源码包第一反应是「直接解压编译不就完了」结果在configure阶段就被 GEOS、PROJ、GDAL 的版本依赖卡住折腾一下午连数据库都没连上。这个包本质上是 PostgreSQL 的空间扩展源码发行版它让普通的关系型数据库具备存储点线面、做距离计算、判断包含关系、执行空间连接的能力。适合两类人一类是需要在自有服务器上从源码编译、精确控制依赖版本的后端或 GIS 工程师另一类是遇到二进制包与系统库不匹配、必须自己动手的运维。它解决的核心问题是——把空间能力以扩展形式挂进 PostgreSQL而不是另起一套空间数据库。接下来我按「先立住原理、再动手复现、最后讲坑」的顺序把这条路径拆开。2. 编译前必须想清楚的三件事依赖、版本与安装路径2.1 为什么源码编译而不是直接用包管理器包管理器装 PostGIS 最省事但生产环境经常遇到两种情况一是系统自带的 PostgreSQL 版本和 PostGIS 二进制包不匹配二是需要指定 GEOS、PROJ 的具体版本以复现某个空间计算行为。源码编译的价值就在这里——你能决定每一个依赖的版本和安装前缀。代价是依赖链要自己理清。PostGIS 3.3.x 这条线依赖 PostgreSQL 服务端开发头文件、GEOS几何运算、PROJ坐标转换、GDAL栅格与格式支持可选但强烈建议、JSON-C、LibXML2。少一个configure就会报错退出。我一般先在干净环境里把依赖装齐再解压源码。下面这套命令是常见做法路径按自己系统调整# 安装编译工具链与核心依赖以常见 Linux 发行版为例 sudo apt-get update sudo apt-get install -y build-essential postgresql-server-dev-15 \ libgeos-dev libproj-dev libgdal-dev libjson-c-dev libxml2-dev # 解压源码包到工作目录 tar -xzf postgis-3.3.6.tar.gz cd postgis-3.3.6 # 查看 configure 支持的关键开关先别急着编译 ./configure --help | grep -E with-geos|with-proj|with-gdal|prefix逻辑说明第一步装的是编译期依赖postgresql-server-dev-15里的 15 要换成你实际运行的 PostgreSQL 主版本号这个数字错了后面pg_config找不到。第二步解压后进入目录。第三步先看帮助确认--with-geos、--with-proj这些开关存在避免凭记忆写错参数。参数说明--prefix决定安装路径默认会装到 PostgreSQL 的扩展目录一般不用改--with-gdal不显式加也可能被自动探测到但显式写更可控。2.2 configure 阶段的关键参数怎么设configure是整个编译过程的分水岭参数设错后面全白搭。核心参数就几个但每个都影响运行时行为参数作用建议值--with-geosconfig指定 GEOS 配置程序路径系统默认即可多版本共存时显式指定--with-projdir指定 PROJ 安装目录坐标转换异常时优先检查这里--with-gdalconfig指定 GDAL 配置程序路径需要栅格支持时必加--with-jsonc启用 JSON-C 支持默认开启用于 GeoJSON 相关功能--without-topology关闭拓扑扩展不需要拓扑关系时加上可省编译时间执行配置时把关心的开关写全./configure \ --with-geosconfig/usr/bin/geos-config \ --with-projdir/usr \ --with-gdalconfig/usr/bin/gdal-config \ --with-jsonc \ 21 | tee configure.log逻辑说明把输出同时写进configure.log出错时不用往上翻屏。参数说明--with-projdir指向 PROJ 的安装前缀不是proj可执行文件路径这点最容易搞混--with-geosconfig指向的是geos-config脚本它负责吐出 GEOS 的头文件和库路径。配置成功后末尾会打印一份摘要列出探测到的各依赖版本务必扫一眼版本号是否符合预期。2.3 编译、安装与扩展注册的完整链路配置通过后编译本身反而简单但安装和注册是两回事很多人卡在「装完了数据库里却找不到扩展」。# 编译-j 后面的数字按 CPU 核数调整 make -j4 # 安装到 PostgreSQL 扩展目录需要写权限 sudo make install # 进入数据库注册扩展先连上目标库 psql -d your_database -c CREATE EXTENSION postgis; psql -d your_database -c SELECT PostGIS_Version();逻辑说明make -j4并行编译加速核数少就写-j2。make install把编译产物复制到pg_config --sharedir指向的目录。真正让数据库认识 PostGIS 的是CREATE EXTENSION它执行扩展目录里的 SQL 脚本创建geometry类型、空间函数和系统表。参数说明your_database换成实际库名PostGIS_Version()返回版本字符串能查出来就说明注册成功。如果报「could not open extension control file」说明make install的路径和当前 PostgreSQL 用的扩展目录不一致用pg_config --sharedir核对。3. 从零跑通第一个空间查询建表、插数据、算距离3.1 建一张带 geometry 列的表并写入数据扩展注册成功后先建一张最简单的空间表把点数据写进去验证整条链路是通的。-- 建表id 主键name 名称geom 存点几何 CREATE TABLE city_poi ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, geom GEOMETRY(Point, 4326) ); -- 插入两个点4326 表示 WGS84 经纬度坐标系 INSERT INTO city_poi (name, geom) VALUES (A点, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)), (B点, ST_SetSRID(ST_MakePoint(116.41, 39.91), 4326)); -- 建空间索引数据量大时查询性能差别明显 CREATE INDEX idx_city_poi_geom ON city_poi USING GIST (geom);逻辑说明GEOMETRY(Point, 4326)限定了几何类型和 SRID写入其他类型会报错这是约束也是保护。ST_MakePoint按经纬度顺序传参经度在前纬度在后写反了位置会跑到地球另一边。ST_SetSRID给几何打上坐标系标记没有它后续距离计算会按平面处理结果偏差很大。参数说明4326是 WGS84 地理坐标系做全球范围数据常用如果只在一个城市内做米级计算投影坐标系更合适。GIST 索引是空间查询的标配不建索引在大表上做范围查询会全表扫描。3.2 用 ST_Distance 和 ST_DWithin 做距离计算距离计算是空间数据库最高频的需求但地理坐标系和投影坐标系下的行为完全不同这里必须说清楚。-- 地理坐标系下算球面距离单位米 SELECT a.name, b.name, ST_Distance(a.geom::geography, b.geom::geography) AS dist_m FROM city_poi a, city_poi b WHERE a.id b.id; -- 查找某点 5000 米范围内的所有点 SELECT name FROM city_poi WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography, 5000);逻辑说明::geography把几何转成地理类型ST_Distance才会按球面算单位是米不转的话在 4326 下算出来是「度」没有物理意义。ST_DWithin判断两点是否在给定距离内配合 GIST 索引能走索引加速比先算距离再比较快得多。参数说明5000是距离阈值单位米a.id b.id避免同一对点算两次。这里有个血泪经验——很多人直接对 4326 的 geometry 调ST_Distance然后困惑结果为什么是零点几其实就是没转 geography。3.3 空间连接把属性和位置关系关联起来空间连接是 PostGIS 真正拉开差距的地方它让「哪些点落在哪个区域内」这类问题一条 SQL 解决。-- 假设有一张区域表 regiongeom 为多边形 SELECT p.name AS poi_name, r.name AS region_name FROM city_poi p JOIN region r ON ST_Contains(r.geom, p.geom); -- 统计每个区域内的点数 SELECT r.name, COUNT(p.id) AS poi_count FROM region r LEFT JOIN city_poi p ON ST_Contains(r.geom, p.geom) GROUP BY r.name ORDER BY poi_count DESC;逻辑说明ST_Contains(r.geom, p.geom)判断点是否在多边形内部注意参数顺序——容器在前、被包含对象在后写反了结果恒为假。第二个查询用LEFT JOIN保证没有点的区域也出现在结果里计数为 0。参数说明ST_Contains要求两个几何的 SRID 一致不一致会报错跨坐标系数据要先ST_Transform统一。如果区域边界上的点算不算包含有争议可以改用ST_Intersects它把边界情况也算进去。4. 避坑与排查源码编译和空间查询里最容易翻车的地方4.1 configure 报找不到 GEOS 或 PROJ现象执行./configure时提示could not find geos-config或PROJ 4.9 required即使系统里明明装了。原因geos-config或proj不在默认 PATH 里或者装的是运行时库没装开发包-dev后缀那个。源码编译需要的是头文件和配置脚本不是只有.so就行。解决先用which geos-config和proj确认可执行文件位置找不到就补装开发包找到了但 configure 仍报错就显式传--with-geosconfig/实际路径/geos-config。PROJ 版本要求这条线通常要 6 以上版本太低只能升级。4.2 编译通过但 CREATE EXTENSION 失败现象make install没报错进数据库执行CREATE EXTENSION postgis却提示找不到控制文件。原因make install装到了编译时pg_config指向的目录而当前连的数据库可能是另一个 PostgreSQL 实例扩展目录不是同一个。解决用pg_config --sharedir看当前实例的扩展目录再确认make install的输出路径是否一致。多实例共存时编译前就把 PATH 里的pg_config指向目标实例或者 configure 时用--with-pgconfig显式指定。4.3 距离计算结果明显偏小或偏大现象两个相距几公里的点ST_Distance算出来是零点零几。原因对 4326 坐标系的 geometry 直接算距离得到的是度数不是米。一度纬度约 111 公里所以零点零几度其实对应几公里数值看着小但单位错了。解决距离计算统一转geography或者把数据投影到合适的平面坐标系如 UTM再算。转 geography 简单但有性能开销数据量大且集中在某一区域时投影坐标系更划算。4.4 空间索引没被用上查询慢得离谱现象建了 GIST 索引但范围查询还是全表扫描几百万行数据查一次要好几秒。原因查询条件里对几何列做了函数运算或类型转换比如ST_Distance(geom, ...) 1000这种写法索引用不上或者查询里用了::geography转换索引列和查询列类型不一致。解决范围查询优先用ST_DWithin而不是ST_Distance 前者能走索引。必须转换类型时考虑建表达式索引或者把数据统一存成查询时用的类型。用EXPLAIN ANALYZE看执行计划确认有没有Index Scan。4.5 升级或重装后扩展版本对不上现象重新编译安装了新版本数据库里PostGIS_Version()还是旧版本号。原因CREATE EXTENSION只在首次注册时执行已存在的扩展不会自动升级。解决用ALTER EXTENSION postgis UPDATE;升级扩展必要时指定目标版本TO 3.3.6。升级前备份数据库空间扩展升级涉及系统表变更出问题回滚成本高。升级后重新ANALYZE相关表让查询计划器拿到最新统计信息。5. 进阶技巧用 EXPLAIN 和边界数据验证空间查询是否真的走对了路编译装好只是起点真正决定这套东西值不值得投入的是空间查询在生产数据量下能不能稳住。我一般用两个手段验证执行计划和边界数据。先看执行计划。空间查询慢九成是索引没走对。下面这个对比很能说明问题-- 可能走索引ST_DWithin 配合 geography 转换 EXPLAIN ANALYZE SELECT id FROM city_poi WHERE ST_DWithin(geom::geography, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography, 5000); -- 大概率不走索引对几何列做距离计算再比较 EXPLAIN ANALYZE SELECT id FROM city_poi WHERE ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint(116.40, 39.90), 4326)::geography) 5000;逻辑说明第一条ST_DWithin是范围判断PostGIS 能把它下推到索引扫描第二条先算每行的距离再比较等于对全表每一行都做一次球面距离计算数据量大时差距是数量级的。参数说明EXPLAIN ANALYZE会真实执行并返回耗时看输出里有没有Index Scan using idx_city_poi_geom有就对了出现Seq Scan就要回头改写法。再看边界数据。空间计算最容易在边界上出玄学问题点正好落在多边形边上、两个多边形只共享一条边、坐标转换后精度丢失导致原本相邻的几何出现缝隙。我的习惯是专门造一组边界测试数据覆盖「内部、边上、顶点、外部」四种位置关系每次改查询或升级版本都跑一遍。比如判断包含关系时ST_Contains不把边界上的点算作包含而ST_Intersects算这两个函数在业务语义上差别很大选错了在边界数据上才会暴露。还有一个容易被忽略的点是坐标系转换的精度。ST_Transform在不同 PROJ 版本下对同一组坐标可能给出微小差异的结果做面积或距离统计时这种差异累积起来可能影响结论。我的做法是涉及精确统计的场景尽量在投影坐标系下计算避免频繁在地理坐标系和投影坐标系之间来回转必须转的时候固定 PROJ 版本并记录在案换版本前先跑一遍回归数据。最后说一个我踩过的坑。早期我图省事把所有几何都存成 4326 的 geometry距离计算临时转 geography小数据量下没感觉数据涨到千万级后查询直接拖垮数据库。后来改成按业务区域投影存储距离和面积计算全部在投影坐标系下做只在出图和对接外部数据时才转回 4326性能稳定了一个数量级。这个教训是坐标系选型要在建表时就定死别指望后期靠转换补救。希望帮到你。本文还有配套的精品资源点击获取