PG实战笔记 | 12 PostgreSQL数据目录与重要文件结构
上一篇我们排查了安装部署的常见问题。这一篇,我们钻进 PGDATA 目录,看看 PostgreSQL 的"身体内部"到底长什么样。理解这些文件和目录的作用,你才能真正理解为什么有些文件不能碰、备份时该包含什么、以及数据库崩溃时到底发生了什么。

一、PGDATA 是什么?
PGDATA 是 PostgreSQL 数据目录的环境变量,指向一个数据库集群(Cluster)的根目录。一个 PG 实例对应一个 PGDATA,里面存放着这个实例下所有数据库的数据、配置、日志和事务信息。
查看当前 PGDATA 路径:
bash
# 通过 psql 查看
SHOW data_directory;
# 通过命令行查看
psql -U postgres -c "SHOW data_directory;"
# 或直接看进程参数
ps aux | grep postgres
典型路径:
| 环境 | 默认 PGDATA 路径 |
|---|---|
| Ubuntu/Debian | /var/lib/postgresql/<版本>/main |
| CentOS/RHEL | /var/lib/pgsql/<版本>/data |
| macOS (Homebrew) | /opt/homebrew/var/postgresql@<版本> |
| 源码编译 | 由 initdb -D 指定 |
进入 PGDATA:
bash
sudo -u postgres ls -la /var/lib/postgresql/17/main/
你会看到类似这样的结构:
base/ global/ pg_commit_ts/ pg_dynshmem/
pg_hba.conf pg_ident.conf pg_logical/ pg_multixact/
pg_notify/ pg_replslot/ pg_serial/ pg_snapshots/
pg_stat/ pg_stat_tmp/ pg_subtrans/ pg_tblspc/
pg_twophase/ pg_wal/ pg_xact/ postgresql.auto.conf
postgresql.conf postmaster.pid postmaster.opts PG_VERSION
下面我们按重要程度逐类拆解。
二、配置文件:控制数据库行为
postgresql.conf:主配置文件
这是 PostgreSQL 最核心的配置文件,控制着数据库的所有运行参数:内存分配、连接数、日志、复制、WAL、查询优化等。
ini
# 关键参数示例
listen_addresses = 'localhost'
port = 5432
shared_buffers = '4GB'
work_mem = '32MB'
max_connections = 200
wal_level = 'replica'
logging_collector = on
log_directory = 'pg_log'
注意: 从 PG 12 开始,postgresql.conf 本身不会被 ALTER SYSTEM 修改。ALTER SYSTEM SET 命令写入的是 postgresql.auto.conf,该文件优先级高于 postgresql.conf。这样做的好处是:手动编辑的配置和系统自动修改的配置分离,升级时更容易管理。
pg_hba.conf:客户端认证配置
"HBAs" 是 Host-Based Authentication 的缩写。这个文件决定哪些客户端、以什么方式、可以连接哪个数据库。
ini
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all 192.168.1.0/24 scram-sha-256
匹配规则:第一匹配优先。 如果有两条规则都匹配,PG 使用第一条,而不是"最精确"的那条。因此规则顺序至关重要。
修改后需要 reload 生效:
bash
sudo systemctl reload postgresql
pg_ident.conf:操作系统用户映射
当 pg_hba.conf 中使用 peer 或 ident 认证方式时,pg_ident.conf 用于把操作系统用户映射为数据库用户。
ini
# MAPNAME SYSTEM-USERNAME PG-USERNAME
mymap root postgres
mymap deploy app_user
例如,系统用户 root 通过 peer 连接时,会被映射为数据库用户 postgres。
PG_VERSION:集群版本标识
一个简单的文本文件,内容只有一行版本号,例如 17。这个文件绝对不能删除或修改。PostgreSQL 启动时会读取它,确认数据目录的版本与当前二进制版本兼容。如果版本不匹配(比如用 PG 16 的二进制启动 PG 17 的数据目录),启动会直接失败。
三、数据文件:真正存放数据的地方
base/:各数据库的数据文件
base/ 目录下,每个子目录对应一个数据库的 OID(对象标识符)。例如:
base/
├── 1/ # template1 数据库
├── 4/ # template0 数据库
├── 5/ # postgres 数据库
├── 16384/ # 用户创建的某个数据库
└── ...
每个数据库目录下,存放着该数据库所有表、索引的数据文件。文件名通常是表或索引的 relfilenode(关系文件节点),而不是表名。
为什么不用表名? 因为 PostgreSQL 允许同一个表在不同的 schema 下重名。用 OID 作为文件名,可以避免命名冲突,也方便系统内部管理。
重要: 不要手动往 base/ 里添加或删除文件。所有数据文件必须由 PostgreSQL 自己管理。
global/:全局系统表
global/ 存放跨数据库共享的系统表,比如:
pg_database:所有数据库的列表pg_authid:角色/用户信息pg_tablespace:表空间信息pg_shdescription:共享对象的注释
这些文件是所有数据库共用的,如果损坏,整个实例可能无法启动。
pg_wal/:预写日志(WAL)
这是 PostgreSQL 最重要的目录之一。WAL(Write-Ahead Log)是崩溃恢复和流复制的基础。
bash
# 查看 WAL 文件
ls -la /var/lib/postgresql/17/main/pg_wal/
你会看到类似这样的文件:
000000010000000000000001
000000010000000000000002
000000010000000000000003
...
每个文件名 24 个十六进制字符,由三部分组成:时间线 ID(8 位)+ 逻辑日志 ID(8 位)+ 段号(8 位)。
pg_wal 的核心作用:
- 崩溃恢复:数据库崩溃后,通过重放 WAL 恢复未写入数据文件的事务;
- PITR:结合基础备份,恢复到任意时间点;
- 流复制:主库把 WAL 发送给备库,备库重放实现同步。
pg_wal 中的文件绝对不能手动删除。 即使某些 WAL 看起来"很旧",它们可能仍被归档或备库需要。删除会导致复制中断或恢复失败。清理 WAL 的唯一正确方式是配置 wal_keep_size、archive_command 或让 checkpoint 自然回收。
从 PG 10 开始,pg_wal 取代了之前的 pg_xlog 目录。
pg_xact/:事务提交状态
pg_xact/(旧称 pg_clog)记录每个事务的提交状态:已提交(committed)、已回滚(aborted)、进行中(in progress)。
每个事务占用 2 个比特位。PostgreSQL 通过这个目录判断某个事务是否已提交,从而决定数据行是否可见。
事务 ID 回卷(Transaction ID Wraparound) 问题就与这个目录有关。事务 ID 是 32 位的,大约 42 亿个。如果数据库长时间不清理旧事务,事务 ID 可能耗尽,导致数据库停止服务。这就是为什么 VACUUM 如此重要。
pg_multixact/:多事务状态
pg_multixact/ 存储多事务(MultiXact) 的状态信息。当多个事务同时对同一行加锁时(比如 SELECT FOR SHARE),PostgreSQL 使用 MultiXact ID 来记录这些事务的组合,而不是为每个事务单独记录。这个目录如果膨胀,可能导致数据库启动变慢或无法启动。
pg_subtrans/:子事务状态
pg_subtrans/ 存储子事务(Subtransaction) 的状态。保存点(SAVEPOINT)和 PL/pgSQL 异常处理块会产生子事务。这个目录通常较小,但同样不能手动清理。
四、其他重要目录
pg_tblspc/:表空间软链接
如果你创建了额外的表空间,pg_tblspc/ 下会有对应的软链接,指向实际的数据目录。
bash
ls -la /var/lib/postgresql/17/main/pg_tblspc/
# lrwxrwxrwx 1 postgres postgres 20 ... 16385 -> /data/tablespace1
备份时必须注意: 表空间的实际数据不在 PGDATA 内,而在软链接指向的目录中。只备份 PGDATA 会丢失表空间数据。
pg_logical/:逻辑复制状态
存放逻辑解码和逻辑复制相关的状态信息,包括快照、映射文件等。如果使用逻辑复制或 CDC,这个目录很重要。
pg_stat/ 和 pg_stat_tmp/:统计信息
存放 PostgreSQL 的运行时统计信息,如 pg_stat_activity、pg_stat_database 的数据来源。这些文件在崩溃后可以重建,不会丢失持久化数据。
pg_replslot/:复制槽
存放复制槽(Replication Slot)的持久化状态。如果使用了逻辑复制槽或物理复制槽,这个目录会记录备库的消费位置。如果备库长时间断连,复制槽会导致主库的 WAL 无法回收,最终撑满磁盘。 这是生产中常见的磁盘告警原因。
五、为什么不能随意删除 PGDATA 中的文件?
PostgreSQL 的每个文件之间都有关联,手动删除一个文件,可能引发连锁反应:
| 删除的文件 | 后果 |
|---|---|
PG_VERSION |
数据库无法启动,报版本不匹配 |
postmaster.pid(进程运行时) |
可能导致两个实例同时运行,数据损坏 |
pg_wal/ 中的 WAL |
崩溃恢复失败、复制中断、PITR 不可能 |
pg_xact/ 中的文件 |
事务状态丢失,数据库无法判断行可见性 |
base/ 中的文件 |
表数据丢失,查询报错 |
global/ 中的文件 |
系统表损坏,整个实例无法启动 |
pg_tblspc/ 软链接 |
表空间数据无法访问 |
核心原则:PGDATA 是 PostgreSQL 的"身体",所有文件都是器官。 任何"清理"或"优化"操作,都应该通过 PostgreSQL 提供的命令(VACUUM、pg_ctl、ALTER SYSTEM)进行,而不是直接操作文件系统。
六、备份时哪些目录必须包含?
物理备份(pg_basebackup / 文件系统快照)
物理备份需要整个 PGDATA 目录,但以下几类可以排除:
| 目录/文件 | 是否必须备份 | 说明 |
|---|---|---|
base/ |
✅ 必须 | 所有数据库数据 |
global/ |
✅ 必须 | 系统表 |
pg_wal/ |
✅ 必须 | 崩溃恢复所需 |
pg_xact/ |
✅ 必须 | 事务状态 |
pg_multixact/ |
✅ 必须 | 多事务状态 |
pg_subtrans/ |
✅ 必须 | 子事务状态 |
pg_tblspc/ |
✅ 必须(含链接目标) | 表空间数据 |
postgresql.conf |
✅ 建议 | 配置恢复 |
pg_hba.conf |
✅ 建议 | 认证配置 |
postgresql.auto.conf |
✅ 建议 | ALTER SYSTEM 配置 |
postmaster.pid |
❌ 不需要 | 启动时自动重建 |
pg_stat_tmp/ |
❌ 不需要 | 运行时临时统计 |
pg_log/ |
⚠️ 可选 | 日志文件,视需求而定 |
pg_basebackup 会自动处理这些。 它会复制整个 PGDATA,包括 WAL,但不包括 postmaster.pid 和临时统计文件。
逻辑备份(pg_dump / pg_dumpall)
逻辑备份只导出 SQL 或归档格式的数据,不涉及 PGDATA 文件结构。但需要注意:
pg_dump只备份单个数据库;pg_dumpall备份所有数据库,包括全局角色和表空间定义;- 逻辑备份不包含
pg_wal、pg_xact等物理文件,因此无法用于 PITR。
表空间的特殊处理
如果你使用了自定义表空间,物理备份必须同时备份:
- PGDATA 目录(含
pg_tblspc/软链接); - 软链接指向的实际表空间目录。
使用 pg_basebackup -T 参数可以将表空间映射到备份目录。
七、快速定位关键文件
日常运维中,以下命令可以帮你快速找到关键文件:
bash
# 查看 PGDATA 路径
psql -c "SHOW data_directory;"
# 查看配置文件路径
psql -c "SHOW config_file;"
psql -c "SHOW hba_file;"
# 查看 WAL 目录
psql -c "SHOW wal_directory;"
# 查看当前 WAL 写入位置
psql -c "SELECT pg_current_wal_lsn();"
# 查看 WAL 文件列表
psql -c "SELECT * FROM pg_ls_waldir() ORDER BY modification DESC LIMIT 10;"
# 查看数据库 OID 与名称对应关系
psql -c "SELECT oid, datname FROM pg_database ORDER BY oid;"
八、总结
PGDATA 目录是 PostgreSQL 的"身体",理解它的结构,你才能理解数据库的行为:
| 类别 | 关键文件/目录 | 作用 |
|---|---|---|
| 配置 | postgresql.conf、pg_hba.conf、postgresql.auto.conf |
控制行为与认证 |
| 版本 | PG_VERSION |
集群版本标识 |
| 数据 | base/、global/ |
用户数据与系统表 |
| 事务 | pg_xact/、pg_multixact/、pg_subtrans/ |
事务状态 |
| 恢复 | pg_wal/ |
崩溃恢复与复制 |
| 扩展 | pg_tblspc/、pg_logical/、pg_replslot/ |
表空间、逻辑复制、复制槽 |
三句话记住核心:
- 不能手动删。 PGDATA 中的文件都有关联,删除任何一个都可能引发连锁故障。
- 备份要完整。 物理备份必须包含
base/、global/、pg_wal/、pg_xact/和表空间实际目录。 - WAL 最特殊。 它既是恢复的基础,也是复制的基础,管理不当会导致磁盘撑满或复制中断。
一句话:PGDATA 不是普通的文件夹,而是 PostgreSQL 的"生命体"。尊重它的结构,它才能稳定运行。
下一篇,我们进入第 4 章 SQL 基础:从 DDL、DML 到查询,打好 SQL 基本功。
思考题:
你有没有遇到过 PGDATA 相关的故障?比如 pg_wal 撑满磁盘、复制槽导致 WAL 无法回收、或者误删文件导致数据库无法启动?欢迎在评论区分享你的经历。