AI时代首先数据库-PostgreSQL实战笔记 | 12 PostgreSQL数据目录与重要文件结构

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 的核心作用:

  1. 崩溃恢复:数据库崩溃后,通过重放 WAL 恢复未写入数据文件的事务;
  2. PITR:结合基础备份,恢复到任意时间点;
  3. 流复制:主库把 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。

表空间的特殊处理

如果你使用了自定义表空间,物理备份必须同时备份:

  1. PGDATA 目录(含 pg_tblspc/ 软链接);
  2. 软链接指向的实际表空间目录。

使用 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/ 表空间、逻辑复制、复制槽

三句话记住核心:

  1. 不能手动删。 PGDATA 中的文件都有关联,删除任何一个都可能引发连锁故障。
  2. 备份要完整。 物理备份必须包含 base/、global/、pg_wal/、pg_xact/ 和表空间实际目录。
  3. WAL 最特殊。 它既是恢复的基础,也是复制的基础,管理不当会导致磁盘撑满或复制中断。

一句话:PGDATA 不是普通的文件夹,而是 PostgreSQL 的"生命体"。尊重它的结构,它才能稳定运行。

下一篇,我们进入第 4 章 SQL 基础:从 DDL、DML 到查询,打好 SQL 基本功。


思考题:

你有没有遇到过 PGDATA 相关的故障?比如 pg_wal 撑满磁盘、复制槽导致 WAL 无法回收、或者误删文件导致数据库无法启动?欢迎在评论区分享你的经历。

相关推荐
Song_RsHt1 小时前
Gateway (上):路由与转发,微服务的统一入口
java·笔记·后端·学习·gateway
小天源1 小时前
智叟云集政策监测技术方案——原文解析、证据提取与可核验摘要
java·服务器·数据库
凤山老林1 小时前
从零搭建企业 OAuth2 授权中心:Spring Boot 集成 Spring Authorization Server 与
数据库·spring boot·spring
小羊没烦恼!1 小时前
在.net中读写config文件的各种方法
java·大数据·运维·服务器·前端·数据库·oracle
骑士雄师2 小时前
《结构化思维》第五章 · 精读回顾(案例版 · 含结构图)
笔记
NocoBase2 小时前
本周更新|优化及缺陷修复
数据库·人工智能·开源·零代码·无代码
xxwl5852 小时前
区域赛算法模版第五章---数学与数论
c++·笔记·算法
大侠归来2 小时前
Redis Cluster 的 16384 个槽(Slot)是什么?
数据库·redis·缓存
墨天梦2 小时前
D26_数据库迁移与可复现构建
数据库·oracle