多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

PostGIS Bundle在Windows下的安装配置与实战避坑全解析

PostGIS Bundle在Windows下的安装配置与实战避坑全解析 简介面向PostgreSQL 14的64位环境这份PostGIS 3.5.0完整扩展安装包用于解决普通数据库难以存储、查询与分析地理空间数据的问题适合GIS开发者、数据工程师和系统管理员快速搭建空间数据能力。作为PostgreSQL最流行的开源空间扩展PostGIS支持点、线、面等几何类型并提供空间索引、坐标转换、拓扑关系判断等函数可用于地图服务、位置分析、城市规划与环境监测等场景。压缩包约130.92MB共含1335个文件主体为951个SQL脚本、79个动态库、75个CSV数据、50个TIF栅格文件及35个GFS文件SQL脚本负责创建扩展对象与函数动态库提供核心运行能力CSV与TIF多用于示例数据和坐标参考目录清晰便于按需部署。包内附依赖组件、坐标系定义及示例数据并集成部分点云与路径分析模块可让开发者在PostgreSQL 14中直接启用PostGIS省去源码编译和依赖排查过程同时加上示例资源便于理解从创建空间数据库到执行空间查询的常用流程。目前已有95人学习下载适合需要高效构建GIS后台服务的团队作为基础环境包使用。1. 拿到 postgis-bundle-pg14-3.5.0x64.zip先别急着解压这个文件名已经把大部分信息写在脸上了postgis-bundle是 Windows 下不用安装程序、解压即用的 PostGIS 完整发行包pg14表示它内置的是 PostgreSQL 14 的运行时3.5.0对应 PostGIS 扩展版本x64说明只能用在 64 位 Windows 上。很多人第一次拿到这种 zip 包会默认它跟普通绿色软件一样解压、双击、完事但 PostGIS 的 bundle 恰恰不是这么回事——它里面塞了数据库服务、空间扩展脚本、GDAL 依赖和一整套命令行工具缺了环境变量配置和扩展初始化psql 连上去也只是一台普通得不能再普通的 PostgreSQL空间函数一个都调不出来。这篇文章就是围绕这个 zip 包展开的落地笔记。适合三类人正在 Windows 上做 GIS / LBS 开发、想省掉 Linux 虚拟机折腾的工程师被各种“安装失败”“扩展不存在”错误卡住的新手以及想搞清楚 bundle 和官方安装器到底差在哪、要不要换成 zip 方案的熟手。接下来我会按“包内部结构 → 安装配置 → 踩坑记录 → 数据实操 → 升级进阶”的顺序把能抄作业的命令和参数都摆在明面上。2. bundle 包的目录结构先搞清楚三个组件分别干什么2.1 bin、lib、share/extension 三层各管什么把postgis-bundle-pg14-3.5.0x64.zip解压后第一眼看到的是一堆目录最核心的是bin、lib、share三个。bin里面放着所有可执行程序包括postgres服务进程、psql客户端、pg_ctl服务控制工具还有后面导入导出 shp 数据时要用的shp2pgsql和pgsql2shp。平时做空间数据迁移绝大多数时间都在跟这六个命令打交道。lib目录里是 PostgreSQL 运行时的动态链接库注意这里不只是数据库本身的库还有 PostGIS 依赖的libgdal、libproj、libgeos等空间计算底层库。bundle 之所以体积偏大很大一部分原因就是把这些原生依赖全部塞进了这一个包换来了“解压即用”的便利代价是你没法单独升级其中某一个库——要升只能等新版本 bundle。share/extension是容易被忽略但最关键的一层。PostGIS 不是一个独立的可执行程序而是一堆 SQL 脚本和 C 语言扩展文件组成的数据库插件。postgis.control文件用来声明扩展名和默认版本postgis--3.5.0.sql这个几百 KB 的脚本会在你执行CREATE EXTENSION postgis时被 PostgreSQL 自动加载把几千个空间函数、类型和操作符注入到数据库里。很多人在这一步翻车报“无法加载扩展”八成是 PostgreSQL 的SHAREDIR路径没指向这个 bundle 的share目录。2.2 为什么 Windows 下 PostGIS 用 zip 而不是 exe 安装包在 Windows 上安装 PostgreSQL 本身有原生安装程序但 PostGIS 却长期没有官方 exe 安装器这是很多新手不理解的地方。常见做法是社区把 PostgreSQL 运行时、PostGIS 扩展、GDAL 依赖打包成 zip让用户自己手动做两件事注册环境变量、初始化数据目录。这个选型是刻意的。PostGIS 的版本迭代很快3.5.0 的脚本要依赖特定版本的 GEOS 和 GDAL 才能编译出正确的空间结果。如果做成 exe 安装器就必须把 PostgreSQL 服务注册、扩展脚本拷贝、依赖库版本检测全部写进安装逻辑出错的概率反而更高。zip 包把选择权交给使用者你可以先试跑、再决定要不要注册成 Windows 服务甚至可以同时解压多个版本做对比测试。缺点也很明显——没有安装向导所有配置都得自己动手这就是本文章第三章要解决的问题。2.3 用表格看懂 bundle 里的关键可执行文件文件用途常见调用场景initdb初始化数据库数据目录首次安装时指定编码和数据目录pg_ctl启停 PostgreSQL 服务pg_ctl start/pg_ctl registerpsql命令行客户端执行 SQL、验证扩展版本shp2pgsql把 ESRI Shapefile 转成 SQL导入 shp 空间数据pgsql2shp把空间查询结果导出成 shp数据交换、备份createdb创建新数据库建库后加载 PostGIS 扩展熟悉这张表的重点不是背命令而是理解 bundle 里“没有安装向导、只有工具链”这个事实。后面所有操作本质上都是在手工执行安装向导原本要做的事情。3. 从解压到跑通空间扩展Windows 下的完整配置流程3.1 解压位置与 PATH 环境变量先立规矩我习惯把 bundle 解压到C:\pgsql这个路径没有空格能避开 PostgreSQL 在 Windows 下对带空格路径的一堆怨念。如果你放到C:\Program Files\pgsql后面配置 GDAL 数据路径时大概率会踩坑这一点在第 4 章会展开讲。解压后第一件事是设置环境变量把bin目录加进 PATH同时新建一个PGSHARE环境变量指向share目录。Windows 上可以用系统设置里的“环境变量”界面也可以直接用 PowerShell 执行[Environment]::SetEnvironmentVariable(Path, $env:Path ;C:\pgsql\bin, User) [Environment]::SetEnvironmentVariable(PGSHARE, C:\pgsql\share, User)这段命令把bin目录追加到用户级 PATH并定义了PGSHARE。PostgreSQL 在启动时会根据PGSHARE查找extension目录下的脚本文件如果这个变量缺失后面执行CREATE EXTENSION postgis就会直接报错。设置完成后重开一个终端窗口让环境变量生效。3.2 初始化数据目录与首次启动环境变量就位后下一步是初始化数据库的数据目录。bundle 自带的 PostgreSQL 14 和官方安装版的行为一致必须先用initdb生成基础系统数据库否则连启动都做不到。initdb -D C:\pgsql\data -E UTF8 --localeC -U postgres这里-D指定数据目录-E UTF8强制数据库编码为 UTF-8--localeC是为了避免 Windows 的中文区域设置把排序规则搞出乱子-U postgres设置超级用户名为postgres。如果你用默认的 locale之后对中文进行ORDER BY或LOWER()时会有意想不到的行为我见过某项目因为这个问题导致中文排序结果跟线上 Linux 环境不一致排查了很久。初始化完成后启动服务pg_ctl -D C:\pgsql\data -l C:\pgsql\pg.log start-l参数把日志写到C:\pgsql\pg.log启动过程如果报错这个日志是第一个排查入口。确认启动成功后先创建业务数据库再用psql加载扩展createdb -U postgres gisdb psql -U postgres -d gisdb -c CREATE EXTENSION postgis; psql -U postgres -d gisdb -c SELECT postgis_full_version();上面postgis_full_version()会返回 PostGIS 的完整版本号以及依赖库GEOS、GDAL、PROJ的版本信息。如果能看到类似POSTGIS3.5.0 [EXTENSION]的输出说明扩展加载成功。需要注意的是CREATE EXTENSION postgis只加载基础功能如果你需要栅格数据支持还要手动创建postgis_raster扩展PostGIS 3.x 以后栅格功能不再默认包含。3.3 注册成 Windows 服务让数据库开机自启开发机可以每次手动pg_ctl start但部署到服务器上就不礼貌了。用pg_ctl register把 PostgreSQL 注册成 Windows 服务是最省心的方式pg_ctl register -N PostgreSQL14_GIS -D C:\pgsql\data -U NT AUTHORITY\NetworkService -P password这里-N指定服务名-D指向数据目录-U是 Windows 运行身份-P是数据库超级用户的密码不是 Windows 密码。注册后用net start PostgreSQL14_GIS启动服务。有个细节如果数据库超级用户的密码是空注册时服务会因为无法通过身份验证而启动失败。而initdb阶段设了-U postgres但没设密码的话必须先psql -c ALTER USER postgres PASSWORD yourpass;把密码补上再注册服务否则会看到一个非常折磨人的“服务启动后又自动停止”事件。这条路径走完bundle 才从“一堆文件”变成“一个可用的 GIS 数据库服务”。很多人栽在只解压不配置上以为 zip 里的 postgres.exe 双击就能开机自启实际上 PostgreSQL 在 Windows 上从设计上就不支持直接双击跑服务。4. 安装与使用避坑PostGIS bundle 最常踩的 5 个坑4.1 路径带空格导致 GDAL 数据加载失败某同事把 bundle 解压到C:\Program Files\PostGIS Bundle执行CREATE EXTENSION postgis_raster;时直接报错提示找不到gdal-data目录下的proj.db。问题出在 GDAL 库初始化时按相对路径找资源文件而路径里有空格导致解析被截断。解决办法是解压到C:\pgsql这类无空格路径或者在postgis.ini里显式指定GDAL_DATA为绝对路径。[postgis] GDAL_DATAC:\pgsql\share\contrib\postgis-3.5\gdal-data PROJ_LIBC:\pgsql\share\contrib\postgis-3.5\proj注意postgis.ini文件一般放在bin目录下bundle 在启动时会去读它如果改完还是报错先确认文件编码是 ANSI 而不是带 BOM 的 UTF-8Windows 上这类玄学问题经常是编码引起的。4.2 多套 PostgreSQL 环境导致 psql 连错版本本机原来装了 PostgreSQL 16 的服务PATH 里已有旧的psql路径把 bundle 的bin目录追加到 PATH 之后执行psql -U postgres连上的可能是旧版的 5432 端口服务。此时查SELECT version()会看到 PostgreSQL 16而CREATE EXTENSION postgis大概率失败因为旧实例的share目录里根本没有 PostGIS 的脚本文件。遇到这种情况先不要急着怀疑 zip 包坏了。执行which psql或where psql看实际调用路径再检查pg_ctl status -D C:\pgsql\data确认 bundle 实例是否真的在跑。我一般会把 bundle 的 bin 路径放在 PATH 最前面并且在新终端里操作避免沿用旧终端的环境变量快照。4.3 服务注册成功后却反复停止密码与权限问题某项目部署时用NT AUTHORITY\NetworkService注册服务启动后服务状态从“正在运行”变成“已停止”事件查看器里只有一句模糊的错误。折腾了半天发现是数据目录C:\pgsql\data的访问权限没放开NetworkService 账户没有读取权限导致postgres.exe一启动就崩溃。解决办法右键数据目录 → 属性 → 安全 → 添加NetworkService账户读写权限。另一种做法是注册成-U postgres用当前登录用户身份运行但这台机器一旦注销登录服务又起不来。所以上线前的最后一件事一定要用net stop和net start完整走一遍服务的停止、启动流程不要只验证手动启动。4.4 中文数据乱码客户端编码与数据库编码不一致数据库用-E UTF8初始化后向表里插入中文地名查出来是一堆问号。问题不在数据本身而在 psql 客户端的客户端编码设置。Windows 的默认终端代码页是 GBKpsql 把 GBK 编码的内容直接传给了 UTF-8 数据库。解决方法是执行SET client_encoding TO UTF8;或者在 psql 启动时加-E参数。更彻底的方案是在环境变量里设置PGCLIENTENCODINGUTF8。另外要注意shp2pgsql 导入数据时如果 shp 文件里有中文属性必须加-W UTF8参数指定源文件编码否则会出现属性乱码而几何数据正常的诡异情况。4.5 空间索引建了却不生效缺 ST_Intersects 条件或没 ANALYZE空间索引在 PostgreSQL 里是通过 GIST 索引实现的创建语法是CREATE INDEX idx_poi_geom ON poi USING GIST (geom);。但建完索引后发现查询依然全表扫描速度没有提升。最常见的原因是查询语句没用空间操作符。PostGIS 的 GIST 索引只对bbox 相交、ST_Intersects、ST_DWithin这类函数生效如果你用ST_Area或者ST_Distance 100这种写法优化器根本不会走空间索引。另一个原因是数据量太小优化器认为全表扫描比索引更快。执行ANALYZE poi;更新统计信息后再配合EXPLAIN ANALYZE看执行计划逐步排除掉这两种情况。5. 让数据真正跑起来空间函数验证与 shp 导入导出5.1 用一张测试表验证空间函数链路扩展加载成功只是开始真正证明环境可用的是能跑通一套“创建空间表 → 插入几何 → 空间查询”的完整链路。下面这一段 SQL 可以直接拷到 psql 里运行CREATE TABLE IF NOT EXISTS test_points ( id serial PRIMARY KEY, name text, geom geometry(Point, 4326) ); INSERT INTO test_points (name, geom) VALUES (站点A, ST_GeomFromText(POINT(116.39 39.90), 4326)), (站点B, ST_GeomFromText(POINT(116.41 39.91), 4326)); CREATE INDEX idx_test_points_geom ON test_points USING GIST (geom); SELECT name, ST_Distance(geom::geography, POINT(116.40 39.905)::geography) AS dist_meters FROM test_points ORDER BY dist_meters;这段 SQL 做了四件事建表时指定几何类型为geometry(Point, 4326)即二维点加 WGS84 坐标系插入数据时用ST_GeomFromText把 WKT 字符串转成几何对象建 GIST 空间索引最后用ST_Distance计算每个点到目标点的球面距离单位为米。注意我把几何对象用::geography转成了地理类型这样距离计算才按椭球模型走结果更符合地图上的直观感受否则 4326 坐标系下算出来的距离是度不是米。如果这段 SQL 能顺利跑完说明几何类型、空间索引、空间函数三大件全部正常。5.2 shp2pgsql导入一个真实 shp 图层拿到一个已有的 shp 文件时shp2pgsql是必用工具。它的工作流程是把 shp 文件解析成 SQL 文件再把 SQL 通过管道喂给 psqlshp2pgsql -s 3857 -I -W UTF8 poi.shp public.poi | psql -U postgres -d gisdb参数含义-s 3857指定 shp 文件自带的坐标系为 Web 墨卡托如果你的 shp 是别的坐标系要改成对应的 EPSG 编号比如 CGCS2000 是4490WGS84 是4326-I表示导入后自动建 GIST 空间索引-W UTF8指定 shp 属性表里的字符串编码如果源文件是 GBK 的把 UTF8 改成 GBK 即可。有一个常见的翻车场景shp 的坐标系是4490CGCS2000但底图数据是3857导入后直接把两个图层叠在一起发现位置偏了几公里。这不是导入命令的问题而是坐标系没统一。最稳妥的做法是导入后用ST_Transform做一次坐标转换统一到3857再使用ALTER TABLE public.poi ALTER COLUMN geom TYPE geometry(MultiPolygon, 3857) USING ST_Transform(geom, 3857);5.3 pgsql2shp把查询结果导出成 shp导出方向同样常用比如把某个时间范围内的轨迹点导出给外业人员看。pgsql2shp的用法跟 shp2pgsql 正好相反它直接连数据库执行查询并生成 shp 文件pgsql2shp -f C:\gis_data\export_poi -u postgres -P password gisdb SELECT id, name, geom FROM public.poi WHERE ST_Within(geom, ST_MakeEnvelope(116.0, 39.5, 117.0, 41.0, 3857))这里-f指定输出文件路径-u和-P是账号密码最后一个参数是数据库名和查询 SQL。需要注意的是导出格式的字段宽度固定为 DBF 规范中文文本超出长度会被截断写 SQL 时用LEFT(name, 20)提前控制长度就能避免乱码和截断问题。6. 版本升级与日常维护把 bundle 用熟的进阶技巧PostGIS 的版本迭代节奏不算慢3.5.0 之后还会有小版本更新。Windows 下升级 postgis 扩展本身不需要重装整个 bundle拿到新版 zip 后解压到一个新目录把新目录的share\extension覆盖到旧目录然后执行ALTER EXTENSION postgis UPDATE;。这里最关键的坑是升级前用pg_dump -Fc做一次全库备份因为扩展升级脚本一旦执行到一半报错数据库可能处于“已更新但不可用”的中间状态没有备份几乎只能从头初始化。日常用得多的另一个技巧是持续关注postgis_full_version()的输出。它除了显示 PostGIS 版本还会报告 GEOS 和 PROJ 的版本如果发现 GEOS 版本过低某些空间计算函数的精度会明显下降这时候才需要整体升级 bundle。我个人的习惯是每半年检查一次这个输出不是看数字新不新而是确认底层依赖没有偏离太远。PostGIS 3.x 之后栅格功能默认不再随主扩展安装。需要用到ST_AsTIFF、ST_Value做栅格计算的项目在创建扩展时要单独执行CREATE EXTENSION postgis_raster;并且要设置postgis.enable_outdb_rasters参数为on否则你只能读本地栅格读不到外部引用栅格。完整命令如下psql -U postgres -d gisdb \ -c CREATE EXTENSION IF NOT EXISTS postgis_raster; \ -c SET postgis.enable_outdb_rasters on;最初用 bundle 包做某图像处理 Demo 的时候我犯过一个很低级的错误把整个 zip 当作“绿色软件”解压后只运行了postgres.exe然后对着 psql 连接失败的错误日志发了一下午的呆。后来把环境变量、数据初始化、扩展加载这三件事理清楚全流程跑通只需要十分钟。Windows 上做 GIS 开发本身不算主流选择但一旦摸清 bundle 的脾气它反而是上手最快、最容易复现的一条规定路线。希望这篇文章能帮你少走一段弯路把时间花在数据本身而不是折腾环境上。本文还有配套的精品资源点击获取
返回列表