1. 为什么这个看似简单的问题值得认真查
PostGIS 是 PostgreSQL 最流行的空间数据扩展,它把 Postgres 从一个传统的关系型数据库变成了能存点、线、面、经纬度、轨迹这些地理对象的空间数据库。做地图类应用、LBS 项目、GIS 数据分析的同学,几乎每天都要和它打交道。
但现实是,很多人装完 PostgreSQL,跑了一圈安装教程,结果第一步就卡住了:我到底装没装上 PostGIS?更常见的情况是,在某些 Linux 发行版里,PostgreSQL 默认不自带 PostGIS,需要额外从软件源安装。而云数据库、Docker 镜像、一键安装包各种来源混在一起,环境差异很大,一个不留神就会在错误的环境里做判断,然后花半天时间排查一个根本不存在的"配置问题"。
也正是因为这件事太基础了,网上回答要么只给一条命令,要么上来就是你"应该"装了什么依赖,反而把问题搞复杂了。这篇文章我会把我平时真正会用到的检查思路、命令、坑点全部写清楚,尽量让不同环境下的人都能直接抄作业。
先说结论,检查 PostgreSQL 是否安装了 PostGIS,最直接的命令是:
SELECT PostGIS_Version();如果返回了类似3.4 USE_GEOS=1 USE_PROJ=1 USE_STATS=1这样的版本信息,说明扩展已经可用。如果报错说函数不存在,那就继续往下看,问题要分多种情况讨论。
2. 核心概念先理清:安装、创建、可用不是一回事
在动手查之前,必须先把三个概念分开。
第一,"PostgreSQL 装了 PostGIS"在操作系统层面是什么意思?通常意味着相关的库文件、SQL 脚本、控制文件被放到了 PostgreSQL 的扩展目录下。比如在 Linux 上,你安装了postgis这个系统包,它会把 PostGIS 的文件拷到/usr/share/postgresql/15/extension/这些位置。
第二,"PostgreSQL 数据库里启用了 PostGIS"是什么意思?PostgreSQL 的扩展(Extension)机制要求你在具体的数据库里显式执行CREATE EXTENSION postgis;才能使用。这是很多人最容易忽略的:系统层面装了 PostGIS,但你的数据库里没启用,照样用不了。
第三,"能不能用"是什么意思?那就是你当前连接的数据库里,PostGIS 的函数、数据类型、操作符是否真的加载进去了。
这个区分之所以重要,是因为你检查出来的结果,对应的解决方案完全不一样。比如:
- 系统里没装 → 安装相关系统包
- 系统装了,但当前数据库没启用 → 执行
CREATE EXTENSION - 当前库启用时报错 → 通常是版本不兼容或文件缺失
网上常见的\dx命令查出来是空的,很多人都以为是"没装上",但实际更有可能是"已经装了但没启用"。这两者的处理路径不同,先搞清楚再动手,能省掉大量无效操作。
3. 四种常用检查方法,从快到慢层层展开
3.1 psql 命令行里查已安装扩展
如果你已经能连上 psql,最快的方式是查看扩展列表。在数据库里执行:
\dx或者查得更细一点:
\dx+ postgis\dx会列出当前数据库所有已安装的扩展,名字、版本、schema、描述都在。如果 postgis 在里面,说明当前数据库已经启用了这个扩展。
很多人对这个命令有误解:\dx显示的是当前数据库的扩展,不是整个数据库实例。同一个 PostgreSQL 实例下,A 库启用了 postgis,B 库不一定有。这是 PostgreSQL 扩展机制决定的,每个库独立维护自己启用了哪些扩展。
所以当你在别的库查不到时,不代表 PostGIS 没装,只代表那个库没启用。需要的话切到对应库再查:
psql -d your_db -c "\dx"3.2 查询系统表确认扩展和版本
不想用\dx,也可以用 SQL 直接查系统表。PostgreSQL 把扩展信息存在两个关键地方。
第一个是pg_extension表,记录当前数据库已启用的扩展:
SELECT extname, extversion FROM pg_extension WHERE extname = 'postgis';如果查到一行,说明当前库已启用。第二个是pg_available_extensions视图,它列出的是系统里所有"可以安装"的扩展(不论当前库有没有启用),这个视图在任意库里都能查:
SELECT name, default_version, installed_version FROM pg_available_extensions WHERE name = 'postgis';这里有一个很有用的字段:installed_version。它表示当前数据库里这个扩展的实际版本。如果该字段为空,说明扩展在系统层面可用,但当前库还没启用。如果它有值,说明已经启用了。
用这种 SQL 方式的好处是方便在脚本、程序里集成判断,不用手动去跑 psql。
3.3 直接调 PostGIS 函数验证
很多时候"查扩展存在"不等于"功能可用",尤其是当你引用的库、文件版本不一致时。所以更稳妥的验证方式是直接调用 PostGIS 提供的函数。
SELECT PostGIS_Version(); SELECT PostGIS_Full_Version(); SELECT postgis_full_version();PostGIS_Full_Version()的输出是最完整的,它会带出 GEOS、Proj、GDAL 这些底层库的版本:
POSTGIS="3.4.1" [EXTENSION] PGSQL="150" GEOS="3.11.2" PROJ="9.1.0" GDAL="3.6.3" LIBXML="2.9.13"注意,PostGIS_Full_Version()这个名字在不同版本里有大小写差异,PostGIS 的函数名大小写不敏感,所以写成postgis_full_version()也没问题。
如果当前库没有启用 postgis,执行这个函数会立刻报错,类似:
ERROR: function postgis_full_version() does not exist HINT: No function matches the given name and argument types.这个报错信息其实是很好的诊断线索:说明当前库里没有 postgis 的函数,那八成是没启用。
3.4 从文件系统层面确认安装状态
如果你连 psql 都还没进去,或者你想确认系统层面的安装情况,可以用操作系统的包管理命令。
以 Ubuntu/Debian 系为例:
dpkg -l | grep postgis或者查具体的包:
apt list --installed | grep postgisCentOS/RHEL/Fedora 系则用:
rpm -qa | grep postgis再狠一点,直接检查扩展文件是否存在。PostgreSQL 的扩展文件通常放在$SHAREDIR/extension/下,你可以先找扩展目录:
pg_config --sharedir然后列出里面的 postgis 相关文件:
ls -l $(pg_config --sharedir)/extension/ | grep postgis正常情况下你能看到类似postgis.control、postgis--3.3.2.sql、postgis--3.3.1--3.3.2.sql之类的文件。postgis.control文件的存在,基本可以认定系统层面已经安装了 PostGIS,只是有没有在当前库启用是另一回事。
不过文件系统层面也有坑。比如有的服务器上有多个 PostgreSQL 版本。你用psql连的可能是一套环境,而pg_config指向的可能是另一套,这样你在文件系统里看到的"已安装"和你在数据库里见到的"用不了"可能同时成立。这种多版本共存的问题,排查起来很烦人,后面我会单独展开。
4. 实操过程:逐步走一遍完整的检查流程
4.1 场景A:全新服务器,还没建库
如果你是在一台刚装好 PostgreSQL 的机器上,想确认环境能不能跑 PostGIS,我建议按下面的顺序来。
先确认 PostgreSQL 版本和安装路径:
psql --version再确认有没有装 PostGIS 相关系统包:
# Ubuntu/Debian dpkg -l | grep postgis # CentOS/RHEL rpm -qa | grep postgis # 或者检查扩展目录 ls -l $(pg_config --sharedir)/extension/ | grep postgis这一步没有输出,那就说明系统层面确实还没装。不同系统的安装方式:
Ubuntu/Debian 系安装 PostgreSQL 15 的 PostGIS:
sudo apt install postgresql-15-postgis-3CentOS/RHEL 系:
sudo dnf install postgis装完再重复一次文件目录检查,确认postgis.control存在了,再进下一步。
然后创建一个测试数据库,启用扩展:
sudo su - postgres -c "createdb gis_test" sudo su - postgres -c "psql -d gis_test -c 'CREATE EXTENSION postgis;'"再调用函数验证:
sudo su - postgres -c "psql -d gis_test -c \"SELECT postgis_full_version();\""如果能看到版本串,这个环境就是可用的了。
4.2 场景B:已有数据库,怀疑扩展没启用
数据库已经在跑,你的应用连上去说找不到 PostGIS 相关类型,这种情况最常见。
先连到对应的业务库:
psql -h 你的主机 -U 你的用户 -d 你的数据库然后执行:
\dx如果没看到 postgis,但你在系统层面确认过已经安装了扩展包,那我建议直接启用:
CREATE EXTENSION IF NOT EXISTS postgis;很多初学者会担心执行这个会不会把已有数据搞坏。一般情况下,PostGIS 扩展只是往数据库里新增类型、函数、表和视图(比如spatial_ref_sys),不会动你已有的表,所以可以放心执行。唯一要留意的是,如果你在此之前已经手动创建过 PostGIS 相关对象,CREATE EXTENSION 会提示对象已存在,此时需要先排查有没有历史遗留的旧版本对象。
启用之后再次执行:
SELECT postgis_full_version();如果这次能正常输出,说明之前的问题就是"没启用"。
4.3 场景C:别人给你的连接串,你想快速验证
有时候你只是拿到一个数据库连接信息,比如host=xxx port=5432 dbname=map user=u password=p,你想远程确认它支不支持 PostGIS。
用一条命令搞定:
PGPASSWORD=p psql -h xxx -p 5432 -U u -d map -c "SELECT postgis_version();"如果远程连接允许,能直接返回 PostGIS 版本。如果返回function does not exist,那基本可以断定这个库没启用扩展。再用下面的 SQL 确认系统层是否可用:
SELECT name, default_version, installed_version FROM pg_available_extensions WHERE name = 'postgis';注意,pg_available_extensions是从当前实例视角来看的,不需要特定数据库。就算当前库没启用,系统装了扩展包,这里也能查出来。这个特性用来区分"没装"和"没启用"是非常有用的。
4.4 实操时要有意识:检查版本兼容矩阵
PostGIS 和 PostgreSQL 之间是有版本兼容关系的。很多人在一个比较新的 PostgreSQL(比如 15、16、17)上装一个老版本 PostGIS,报错是跑不掉的。
以常见的 PostGIS 3.x 系列为例:
| PostgreSQL 版本 | PostGIS 3.2 | PostGIS 3.3 | PostGIS 3.4 |
|---|---|---|---|
| 13 | 支持 | 支持 | 支持 |
| 14 | 支持 | 支持 | 支持 |
| 15 | 支持 | 支持 | 支持 |
| 16 | 需确认补丁版本 | 支持 | 支持 |
| 17 | 不支持 | 需确认 | 支持 |
这是我个人实践中整理的粗略对照,具体以官方 Release Notes 为准。在检查安装的时候,如果发现版本组合比较奇怪,比如 PostgreSQL 17 配 PostGIS 3.2,那就别浪费时间折腾配置问题了,先考虑更换版本。
5. 常见问题与排查技巧实录
5.1 能查到扩展列表,但 CREATE EXTENSION 失败
这个场景我碰到过不少次。pg_available_extensions里明明列出了 postgis,默认版本也存在,但是执行:
CREATE EXTENSION postgis;却报错:
ERROR: could not open extension control file或者:
ERROR: could not open extension file ...: No such file or directory这种情况通常意味着系统里只有控制文件的元数据,或者 SQL 脚本文件丢失。常见于某些操作系统的软件包安装不完整、手动拷贝扩展文件时漏拷了脚本,或者同一个 PostgreSQL 实例下扩展目录指向了错误的位置。
排查思路:先确认扩展目录里的文件是不是完整的。一个合法的 PostGIS 扩展至少要有:
postgis.controlpostgis--<版本>.sql- 各个升级脚本,如
postgis--3.3.2--3.4.0.sql
如果这些文件都齐全,那可能是权限问题。PostgreSQL 进程用户(通常是 postgres)对目录没有读权限,就会报类似找不到文件的错。
5.2 启用了扩展,但函数还是找不到
有一个非常容易掉进去的坑:你确实在数据库里执行了CREATE EXTENSION postgis;,但换了一个数据库连接,又提示函数不存在。
原因大概率是:你新连的这个库,根本就没启用扩展。因为扩展是按数据库管理的,你 A 库启用了,B 库默认是没有的。很多框架连接池会串库,或者你的服务配置指向了不同的库,就会产生这种"时好时坏"的诡异现象。
解决方式也很直接,在目标库里也执行一次CREATE EXTENSION IF NOT EXISTS postgis;即可。
5.3 版本太旧,提示需要升级
PostgreSQL 升级大版本后,PostGIS 扩展经常需要跟着升级。当你执行某些 PostGIS 函数时,有时会看到类似:
WARNING: PostGIS extension not upgraded, consider running ALTER EXTENSION postgis UPDATE这是 PostgreSQL 在提醒你,当前库里的 PostGIS 扩展版本低于系统里可用的最新版本。要处理也很简单:
ALTER EXTENSION postgis UPDATE;这个操作会尝试把扩展升级到默认版本。如果你的库里存有大量空间数据,升级前还是建议先备份,因为某些大版本升级或多版本跨度的升级涉及底层格式变化。
5.4 多个 PostgreSQL 版本共存导致的混乱
服务器上同时装了 PostgreSQL 14 和 15 是比较常见的。你通过apt install装了一个 postgis,它只会装到对应的那个 PostgreSQL 版本中。但是你的 psql 可能默认连的是另一个版本。
排查的时候一定要搞清楚你连的到底是哪一套。用以下命令可以确认:
SELECT version();或者从 psql 里看一下:
psql -c "show server_version;"然后再用同一个版本的pg_config去确认扩展文件目录,避免用 A 版本的命令检查 B 版本的环境。
还有个更隐蔽的坑:某些 Linux 发行版会把postgis的扩展文件安装到了 PostgreSQL 全局扩展目录,但控制文件里的版本号和实际 SQL 脚本不匹配。这种属于打包瑕疵,遇到只好手动修正或换源重装。
5.5 云数据库和托管环境怎么查
如果你用的是云厂商提供的数据库服务,你通常连 psql 的权限都不是超级用户,甚至无法直接查看文件系统。这时候判断 PostGIS 是否可用,用的还是上面提到的 SQL 方式。
你可以用\dx或者:
SELECT * FROM pg_available_extensions WHERE name LIKE 'postgis%';如果你在托管环境里看不到 postgis,大概率是服务商没启用这个插件,或者没给你开启扩展的权限。这时候需要去控制台看有没有相关插件开关,或者联系技术支持,而不是自己在库里折腾。
6. 进阶技巧:用一条 SQL 完成整套检查
如果你需要在脚本或者部署流程里做自动判断,我建议写一个综合查询,一次性拿到你想要的关键信息。下面这个 SQL 是我实际用过的,可以同时看到系统可用版本和当前库已安装版本:
SELECT e.name, e.default_version, e.installed_version, CASE WHEN e.installed_version IS NULL THEN 'NOT_ENABLED' ELSE 'ENABLED' END AS status FROM pg_available_extensions e WHERE e.name = 'postgis';这个语句在任何数据库里执行都会返回一行。如果installed_version非空,说明当前库已经启用。如果你还需要确认功能是否正常,再跟一句:
SELECT postgis_full_version();两条 SQL 组合起来的判断逻辑非常清晰,适合放到自动化脚本里。
如果你是运维,还要考虑更多。比如,用 Docker 部署时,官方 PostgreSQL 镜像默认也内置了 PostGIS 吗?不是的,官方镜像只是基础 PostgreSQL,PostGIS 需要你在 Dockerfile 里额外安装,或者直接使用专门的postgis/postgis镜像。如果你是 Kubernetes 环境,那还得关注自己的底包有没有正确安装依赖,不能只看数据库层有没有扩展记录。
结语
最后分享一点我的个人习惯:每次排查 PostGIS 安装问题时,我从来不会只查一种状态。我会把系统层面、数据库层面、函数功能层面三者的结论都拿到,然后再去判断问题到底出在哪一层。很多人花了一晚上调参数,最后发现其实只是没在业务库里CREATE EXTENSION,这种感觉我体会太深了。
如果你是在一个刚接手的老项目里做检查,先跑一次上面说的综合 SQL,再看一眼spatial_ref_sys表和geometry_columns视图是否存在,基本就掌握全局了。真正把这几条命令用熟,后面不管是开发调试还是排障,都能少走很多弯路。