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_mem64MB~256MB排序、哈希、空间连接的内存上限
maintenance_work_mem512MB~1GB加速 GiST 空间索引创建
max_connections100~200连接数上限,需与连接池配合
timezoneAsia/Shanghai数据库会话默认时区
client_encodingUTF8客户端字符编码

字符集在数据库创建时确定,后续修改成本较高,因此建议一开始就使用 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 可用,整个空间数据库实例即验证通过。

PostgreSQL + PostGIS 空间实例验证链路 运行环境 Linux 主机 / Docker 容器 PostgreSQL 16 服务 数据目录持久化挂载 数据库扩展 postgis postgis_topology pgrouting 关键参数 UTF8 / Asia/Shanghai shared_buffers / work_mem PgBouncer 连接池 端到端可用性验证 1. 创建数据库 UTF8 + 时区 2. 启用扩展 postgis / pgrouting 3. 建表插点 geometry(Point,4326) 4. 距离计算 ST_Distance geography 判断依据 距离返回约 890 米 + pgr_version() 正常 = 实例可用 示例参数与结果仅用于教学验证,实际值以执行环境为准
提示:如果 CREATE EXTENSION postgis 报错,先确认 postgresql-16-postgis-3 是否安装成功,以及当前用户是否有超级用户权限。容器环境则确认镜像标签是否包含 PostGIS。
注意:不要在生产环境直接使用 POSTGRES_PASSWORD=spatial123 这类弱密码;连接池的 auth_file 也要设置文件权限,避免明文密码泄露。