2. PostgreSQL与PostGIS环境搭建
空间数据库平台的第一步不是写 SQL,而是把“能连上、能算几何、能跑路径、时区字符集正确”的运行底座搭起来。本节围绕 Linux 主机与容器两条主线,完成 PostgreSQL、PostGIS、pgRouting 的安装与扩展启用,配置空间数据库关键参数、字符集、时区与连接池,并用一个最小空间实例验证可用性。
一、安装路径选择:主机包管理 vs 容器镜像
在 Linux 上安装 PostgreSQL 有两条常见路径。第一条是使用发行版仓库或 PGDG 官方仓库安装,适合需要长期驻留、直接访问主机文件系统、与系统服务集成的生产环境。第二条是使用容器镜像,适合快速搭建、版本隔离、CI 验证和开发环境。两者并不冲突,很多团队用容器做开发验证,用主机安装做生产部署。
以 Ubuntu 22.04 为例,使用 PGDG 仓库安装 PostgreSQL 16 与 PostGIS 3.4 的典型命令如下:
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
sudo apt install -y postgresql-16 postgresql-16-postgis-3 postgresql-16-pgrouting
安装完成后,PostgreSQL 会以系统服务方式运行。使用 pg_lsclusters 可以查看集群状态,使用 psql --version 确认客户端版本。容器方式则更直接,官方 PostGIS 镜像已经预装了 PostGIS,pgRouting 需要额外安装或选择带 pgrouting 的镜像标签:
docker run -d --name pgspatial \
-e POSTGRES_PASSWORD=spatial123 \
-e POSTGRES_DB=gisdb \
-e TZ=Asia/Shanghai \
-p 5432:5432 \
-v /data/pgdata:/var/lib/postgresql/data \
postgis/postgis:16-3.4
这里 TZ=Asia/Shanghai 只影响容器系统时区,数据库内部时区仍需通过参数设置。挂载 /data/pgdata 是为了让数据持久化,避免容器删除后数据丢失。
二、创建空间数据库与启用扩展
安装完软件后,需要创建业务数据库并启用扩展。PostGIS 扩展必须安装到目标数据库中,而不是全局安装。以下命令创建一个使用 UTF8 编码、时区为 Asia/Shanghai 的数据库,并启用 PostGIS 与 pgRouting:
CREATE DATABASE gisdb
WITH ENCODING 'UTF8'
LC_COLLATE='zh_CN.UTF-8'
LC_CTYPE='zh_CN.UTF-8'
TEMPLATE=template0;
\c gisdb
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
CREATE EXTENSION pgrouting;
执行 SELECT postgis_full_version(); 可以查看 PostGIS 版本、GEOS、PROJ、GDAL 等依赖库版本。如果返回结果中包含 POSTGIS="3.4.0" 且 pgrouting 扩展已启用,说明空间计算与路径分析能力已经就绪。注意:postgis_topology 不是所有场景都需要,如果只做基础几何分析,可以只启用 postgis。
三、空间数据库参数、字符集与时区
空间数据往往包含大量几何对象和索引,默认参数可能不够用。以下参数建议在 postgresql.conf 或容器启动参数中调整:
| 参数 | 建议值 | 作用 |
|---|---|---|
| shared_buffers | 物理内存的 25% | 缓存数据页,提升几何查询命中率 |
| work_mem | 64MB~256MB | 排序、哈希、空间连接的内存上限 |
| maintenance_work_mem | 512MB~1GB | 加速 GiST 空间索引创建 |
| max_connections | 100~200 | 连接数上限,需与连接池配合 |
| timezone | Asia/Shanghai | 数据库会话默认时区 |
| client_encoding | UTF8 | 客户端字符编码 |
字符集在数据库创建时确定,后续修改成本较高,因此建议一开始就使用 UTF8。时区可以通过 ALTER DATABASE gisdb SET timezone TO 'Asia/Shanghai'; 设置,也可以在每个会话中执行 SET timezone='Asia/Shanghai';。对于跨时区团队,建议统一使用 UTC 存储,展示时再转换,避免时间语义混乱。
四、连接池配置
空间数据库的查询通常比普通业务查询更重,连接池可以显著降低连接建立开销并控制并发。PgBouncer 是最常用的轻量连接池。典型配置如下:
[databases]
gisdb = host=127.0.0.1 port=5432 dbname=gisdb
[pgbouncer]
listen_port = 6432
listen_addr = 0.0.0.0
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 200
default_pool_size = 20
pool_mode = transaction 表示连接在事务结束后归还池中,适合大多数 Web 应用。如果应用使用了会话级临时表或 SET 会话变量,则需要使用 session 模式。连接池配置完成后,应用连接 6432 端口而不是 5432 端口。
五、可用性验证:首个空间实例
环境搭建是否成功,不能只看安装日志,必须做一次端到端验证。以下 SQL 创建一个点表、插入两个点、计算距离并输出结果:
CREATE TABLE demo_poi (
id serial PRIMARY KEY,
name text,
geom geometry(Point, 4326)
);
INSERT INTO demo_poi (name, geom) VALUES
('天安门', ST_SetSRID(ST_MakePoint(116.397, 39.908), 4326)),
('故宫', ST_SetSRID(ST_MakePoint(116.397, 39.916), 4326));
SELECT a.name, b.name,
ST_Distance(a.geom::geography, b.geom::geography) AS meters
FROM demo_poi a, demo_poi b
WHERE a.name = '天安门' AND b.name = '故宫';
预期结果约为 890 米左右(示例值,实际以执行结果为准)。如果查询成功返回距离,说明 PostGIS 几何类型、SRID、地理计算和 SQL 执行链路全部正常。再执行 SELECT pgr_version(); 确认 pgRouting 可用,整个空间数据库实例即验证通过。
CREATE EXTENSION postgis 报错,先确认 postgresql-16-postgis-3 是否安装成功,以及当前用户是否有超级用户权限。容器环境则确认镜像标签是否包含 PostGIS。
POSTGRES_PASSWORD=spatial123 这类弱密码;连接池的 auth_file 也要设置文件权限,避免明文密码泄露。