简介:PostGIS 3.3.6 源码安装包面向需要在 PostgreSQL 上构建空间数据库能力的开发者与 GIS 工程师,解决地理数据存储、检索、分析与坐标转换等需求。资源共约2000个文件,压缩包16.98MB,以457个sql脚本、269个C源码、127个头文件、418个po多语言文件为主,另含wkt、shp、dbf等空间数据样例与expected回归测试文件,覆盖核心扩展、拓扑、栅格及导入导出工具模块。已有69人学习下载。通过该源码包可完成编译安装并激活PostGIS扩展,掌握空间数据类型、空间索引、空间函数与操作符、空间关系分析及多坐标参考系统转换等能力,同时借助回归测试用例理解各功能模块的验证方式,适合需要深入定制或二次开发空间数据库的读者参考。
1. 拿到 postgis-3.3.6.tar.gz 先别急着解压:这份源码包到底解决什么问题
如果你手上正好有一个 PostgreSQL 实例,业务里开始出现「附近 5 公里内的门店」「两个多边形是否相交」「轨迹点落在哪个行政区」这类需求,纯靠float字段加经纬度硬算,迟早会翻车。postgis-3.3.6.tar.gz 就是给 PostgreSQL 补上空间数据处理能力的那份源码包,解压后能看到shp2pgsql.1、pgsql2shp.1、pgtopo_import.1、pgtopo_export.1这些手册页,以及lwgeom_topo.c、rtpg_mapalgebra.c、postgis_topology.c、shp2pgsql-gui.c、shpopen.c等核心源文件。它把点、线、面、多点、线串、面片集合这些几何类型直接做进数据库,配合 R 树空间索引和一套 SQL 空间函数,让「空间关系判断」从应用层挪到数据库层。适合谁?正在用 PostgreSQL 做 GIS 后端、需要自编译扩展、或者想搞清楚 PostGIS 内部拓扑与栅格实现的人。如果你只是想要一个能跑的空间库,二进制包更省事;但如果你要控版本、控编译参数、或者要读源码定位问题,这份 tar.gz 就是起点。
2. 从 tar.gz 到可用扩展:编译链路与依赖怎么配
2.1 先看清源码包里有什么,再决定编译顺序
解压之后别急着./configure。先扫一眼顶层目录,确认configure、GNUmakefile、README.postgis在不在,再进liblwgeom/、postgis/、topology/、raster/这几个子目录看结构。lwgeom_topo.c属于 liblwgeom 的拓扑支持层,postgis_topology.c是 topology 扩展的入口,rtpg_mapalgebra.c是栅格 map algebra 的实现,shpopen.c和shp2pgsql-gui.c则服务于 shapefile 导入导出。编译顺序上,liblwgeom 必须先于 postgis 核心,topology 和 raster 又依赖核心。常见做法是:
tar -xzf postgis-3.3.6.tar.gz cd postgis-3.3.6 ./configure --with-pgconfig=/usr/local/pgsql/bin/pg_config \ --with-geosconfig=/usr/local/geos/bin/geos-config \ --with-projdir=/usr/local/proj \ --with-jsonconfig=/usr/bin/json-c-config \ --with-gdalconfig=/usr/local/gdal/bin/gdal-config--with-pgconfig指向目标 PostgreSQL 的pg_config,这一步决定扩展装到哪个实例;--with-geosconfig提供几何运算后端;--with-projdir负责坐标参考系统转换;--with-jsonconfig支撑 GeoJSON 输入输出;--with-gdalconfig让栅格和更多格式可用。少一个依赖,configure阶段就会报缺库,别硬扛,按提示补。
2.2 编译、安装、建扩展三步不能省
配置通过后:
make -j$(nproc) sudo make installmake -j并行编译能省时间,但如果你在低内存机器上跑,-j开太大容易 OOM,改成-j2更稳。make install会把postgis.control、SQL 脚本和.so文件拷到 PostgreSQL 的扩展目录。接着进数据库:
CREATE EXTENSION postgis; CREATE EXTENSION postgis_topology; CREATE EXTENSION postgis_raster;CREATE EXTENSION postgis是必选,topology 和 raster 按需。执行完用SELECT PostGIS_Version();验证,返回版本串就说明核心已加载。如果报could not open extension control file,说明make install没把文件放到当前实例的sharedir/extension下,回去检查pg_config --sharedir的路径是否和你安装时一致。
2.3 导入导出工具链:shp2pgsql 与 pgsql2shp 的实际用法
源码包里的shp2pgsql.1和pgsql2shp.1是手册页,对应两个命令行工具。把 shapefile 灌进数据库:
shp2pgsql -s 4326 -I -W GBK roads.shp public.roads | psql -d gisdb-s 4326指定 SRID,-I建空间索引,-W GBK处理中文属性编码。反过来导出:
pgsql2shp -f export_roads -h localhost -u gis -P secret gisdb "SELECT * FROM roads WHERE type='primary'"-f是输出前缀,最后跟的是 SQL 查询。这两个工具在 3.3.6 里已经比较成熟,但编码和 SRID 不匹配时仍会出乱码或坐标偏移,导入前先用prj文件确认坐标系。
3. 空间索引与查询计划:为什么你的 ST_Intersects 还是慢
3.1 R 树索引不是建了就行,得让查询用上
PostGIS 默认用 GiST 索引,建法:
CREATE INDEX idx_roads_geom ON roads USING GIST (geom);但索引建了不代表查询会走。下面这个写法:
SELECT * FROM roads WHERE ST_Intersects(geom, ST_GeomFromText('POLYGON((...))', 4326));在表数据量大时可能全表扫。原因是ST_Intersects本身是精确判断,优化器需要先用索引算子&&做包围盒过滤。常见做法是显式加上:
SELECT * FROM roads WHERE geom && ST_MakeEnvelope(116.0, 39.0, 117.0, 40.0, 4326) AND ST_Intersects(geom, ST_GeomFromText('POLYGON((...))', 4326));&&走索引,ST_Intersects做精筛。用EXPLAIN ANALYZE看执行计划,出现Index Scan using idx_roads_geom才算对。如果还是 Seq Scan,检查列上是不是有函数包裹、或者统计信息太旧,ANALYZE roads;一下。
3.2 坐标系不统一是空间查询最大的黑匣子
很多「查不到结果」不是函数写错,而是 SRID 不一致。比如几何列存的是 4326,你拿 3857 的几何去比,包围盒根本对不上。统一做法:
SELECT ST_Transform(geom, 3857) FROM roads WHERE id = 1;或者建表时就定好 SRID,后续所有输入都ST_Transform到同一坐标系。spatial_ref_sys表里存着所有支持的 CRS,SELECT * FROM spatial_ref_sys WHERE srid = 4326;能确认定义是否存在。如果自定义坐标系没进去,转换会直接报错。
3.3 几何有效性:ST_IsValid 与 ST_MakeValid 的配合
从外部导入的多边形经常自相交或环方向不对,导致ST_Intersects、ST_Area结果异常。先查:
SELECT id, ST_IsValid(geom), ST_IsValidReason(geom) FROM parcels WHERE NOT ST_IsValid(geom);修复:
UPDATE parcels SET geom = ST_MakeValid(geom) WHERE NOT ST_IsValid(geom);ST_MakeValid会把自相交面拆成多面或修正环方向。注意它可能改变几何类型,比如 POLYGON 变 MULTIPOLYGON,后续查询要兼容。批量修复前先备份,别问我怎么知道的。
4. 拓扑与栅格:pgtopo_import 和 rtpg_mapalgebra 能做什么
4.1 拓扑扩展的导入导出链路
pgtopo_import.1和pgtopo_export.1对应拓扑数据的导入导出。拓扑模型把几何拆成节点、边、面,适合路网、行政区划这类需要维护共享边界的场景。建拓扑:
SELECT CreateTopology('city_topo', 4326); SELECT AddTopoGeometryColumn('city_topo', 'public', 'blocks', 'topo_geom', 'POLYGON');导入时用pgtopo_import把外部拓扑数据灌进来,导出用pgtopo_export。postgis_topology.c里实现了拓扑一致性的核心逻辑,比如边的分裂与合并。实际用的时候,拓扑层和普通几何层可以共存,但拓扑层更新要走ST_NewEdgesSplit、ST_ModEdgeHeal这类函数,直接 UPDATE 几何会破坏拓扑关系。
4.2 栅格 map algebra 的典型用法
rtpg_mapalgebra.c支撑栅格代数运算。加载栅格扩展后:
CREATE TABLE dem (rid serial primary key, rast raster); INSERT INTO dem (rast) SELECT ST_FromGDALRaster(pg_read_binary_file('/data/dem.tif'));做坡度计算或波段运算时,用ST_MapAlgebra:
SELECT ST_MapAlgebra(rast, 1, '32BF', '([rast.val] - 100) * 2') FROM dem WHERE rid = 1;表达式里[rast.val]引用像元值,输出类型32BF是 32 位浮点。栅格瓦片太大时先ST_Tile切分,否则单次运算内存扛不住。ST_SummaryStats可以快速看分布,避免盲目跑全图。
5. 避坑与排查:编译、索引、编码、拓扑四类翻车记录
5.1 现象:configure 报找不到 geos_c.h
原因:GEOS 开发头文件没装或路径没给对。 解决:确认geos-config --cflags能输出 include 路径,./configure时显式加--with-geosconfig,别依赖默认搜索。
5.2 现象:CREATE EXTENSION postgis 报 version mismatch
原因:之前装过旧版 PostGIS,扩展目录里残留旧 control 文件。 解决:make uninstall清掉旧文件,或者手动删sharedir/extension/postgis*,再重新make install。升级时用ALTER EXTENSION postgis UPDATE;而不是直接覆盖。
5.3 现象:shp2pgsql 导入后中文属性乱码
原因:shapefile 的.dbf编码和-W参数不一致。 解决:先用ogrinfo或dbfdump确认实际编码,GBK 就-W GBK,UTF-8 就-W UTF-8。导入后SELECT出来还是乱,检查数据库client_encoding和server_encoding。
5.4 现象:ST_Intersects 返回空,但肉眼看着明明相交
原因:两个几何 SRID 不同,或者其中一个几何无效。 解决:SELECT ST_SRID(a.geom), ST_SRID(b.geom)对比,不一致先ST_Transform;再ST_IsValid查有效性,无效就ST_MakeValid。两个都排掉,基本能定位。
5.5 现象:拓扑导入后边要素重复或断裂
原因:源数据本身有悬挂边或重复节点,pgtopo_import不会自动去重。 解决:导入前用ST_Node或ST_Union做一次线要素合并,确保节点唯一。导入后用SELECT * FROM city_topo.edge WHERE geom IS NULL;查异常边。
6. 进阶技巧:用 ST_Subdivide 和空间聚合把大几何查询压到秒级
大区域多边形和百万级点做ST_Intersects,即使有索引也容易慢,因为单个大几何的包围盒覆盖太广,索引过滤效果差。我一般会先用ST_Subdivide把大面切成小块:
CREATE TABLE region_sub AS SELECT id, ST_Subdivide(geom, 256) AS geom FROM region; CREATE INDEX idx_region_sub_geom ON region_sub USING GIST (geom);256是每个子块最多顶点数,数值越小切得越碎,索引过滤越精准,但行数膨胀。切完再和点表做空间连接:
SELECT p.id, r.id AS region_id FROM points p JOIN region_sub r ON ST_Intersects(p.geom, r.geom);配合EXPLAIN ANALYZE对比切分前后的执行计划,通常能从几十秒降到一两秒。另一个技巧是空间聚合:
SELECT r.id, COUNT(p.id) AS cnt FROM region_sub r LEFT JOIN points p ON ST_Intersects(p.geom, r.geom) GROUP BY r.id;如果只要计数,ST_Contains和ST_Intersects在点面场景下结果一致,但ST_Contains有时能走更优的索引路径,可以都试一下看计划。
验证方法上,我习惯用ST_AsText抽样看几何是否正确,用ST_Area和ST_Perimeter做数值 sanity check,再用pg_stat_user_tables看索引命中率。从那以后我每次建完空间索引,都强制走一遍EXPLAIN ANALYZE加ST_IsValid检查,不看到Index Scan不罢休。希望帮到你。
本文还有配套的精品资源,点击获取