本节在文件和目录的层面上描述存储格式。
按照传统做法,一个数据库集簇所用的配置和数据文件都一起存放在集簇的数据
目录中,该目录通常被称为 PGDATA(得名于可用于定义它的
环境变量的名字)。PGDATA 的常见位置是
/var/lib/pgsql/data。同一台机器上可以存在由不同服务器
实例管理的多个集簇。
PGDATA 目录包含若干子目录和控制文件,如
Table 66.1 所示。除这些必需的条目之外,
集簇配置文件 postgresql.conf、
pg_hba.conf 和 pg_ident.conf
按照传统也存放在 PGDATA 中,但也可以放在其他位置。
Table 66.1. PGDATA 的内容
| Item | Description |
|---|---|
PG_VERSION | 包含 PostgreSQL 主版本号的文件 |
base | 包含各数据库子目录的子目录 |
current_logfiles | 记录日志收集器当前正在写入的日志文件的文件 |
global | 包含集簇范围的表的子目录,例如 pg_database |
pg_commit_ts | 包含事务提交时间戳数据的子目录 |
pg_dynshmem | 包含动态共享内存子系统所用文件的子目录 |
pg_logical | 包含逻辑解码状态数据的子目录 |
pg_multixact | 包含多事务状态数据(用于共享行锁)的子目录 |
pg_notify | 包含 LISTEN/NOTIFY 状态数据的子目录 |
pg_replslot | 包含复制槽数据的子目录 |
pg_serial | 包含已提交的可串行化事务信息的子目录 |
pg_snapshots | 包含已导出快照的子目录 |
pg_stat | 包含统计子系统的永久文件的子目录 |
pg_stat_tmp | 包含统计子系统的临时文件的子目录 |
pg_subtrans | 包含子事务状态数据的子目录 |
pg_tblspc | 包含指向表空间的符号链接的子目录 |
pg_twophase | 包含已预备事务的状态文件的子目录 |
pg_wal | 包含 WAL(预写式日志)文件的子目录 |
pg_xact | 包含事务提交状态数据的子目录 |
postgresql.auto.conf | 用于存储由 ALTER SYSTEM 设置的配置参数的文件 |
postmaster.opts | 记录服务器上一次启动时所带命令行选项的文件 |
postmaster.pid | 一个锁文件,记录当前的 postmaster 进程 ID(PID)、集簇数据目录路径、postmaster 启动时间戳、端口号、Unix 域套接字目录路径(可能为空)、第一个有效的 listen_address(IP 地址或 *,如果未监听 TCP 则为空)以及共享内存段 ID(服务器关闭后该文件不存在) |
集簇中的每个数据库在 PGDATA/base
下都有一个以其在 pg_database 中的 OID 命名的
子目录。这个子目录是该数据库文件的默认位置;特别地,它的系统目录就存放
在这里。
注意,以下各节描述的是内建 heap
表访问方法以及内建
索引访问方法的行为。由于
PostgreSQL 的可扩展性质,其他访问方法的工作
方式可能有所不同。
每个表和索引都存储在单独的文件中。对于普通关系,这些文件以表或索引的
filenode 号命名,该号可在
pg_class.relfilenode 中
找到。但对于临时关系,文件名形如
t,
其中 BBB_FFFBBB 是创建该文件的后端进程号,
FFF 是 filenode 号。无论哪种情况,除主文件(即
main fork)之外,每个表和索引还有一个空闲空间映射(见
Section 66.3),它存储关于该关系中可用空闲空间的信息。空闲空间
映射存储在一个以 filenode 号加上 _fsm 后缀命名的文件
中。表还有一个可见性映射,存储在以 _vm
为后缀的 fork 中,用于跟踪哪些页面已知没有死元组。可见性映射在
Section 66.4 中有进一步描述。非日志表和索引有第三个
fork,称为初始化 fork,存储在以 _init 为后缀的 fork
中(见 Section 66.5)。
注意,虽然表的 filenode 常常与其 OID 相同,但这并非
必然;某些操作,例如 TRUNCATE、REINDEX、
CLUSTER 以及某些形式的
ALTER TABLE,可以在保留 OID 的同时改变 filenode。
请避免假定 filenode 与表 OID 相同。
此外,对于包括 pg_class 本身在内的某些系统目录,
pg_class.relfilenode
为零。这些目录实际的 filenode 号存储在一个更低层级的数据结构中,可以用
pg_relation_filenode() 函数获得。
当表或索引超过 1 GB 时,它会被划分为若干以 GB 为单位的
段。第一个段的文件名与 filenode 相同;后续的段
命名为 filenode.1、filenode.2 等。这种安排避免了在具有文件大小限制的
平台上出现问题。
(实际上,1 GB 只是默认的段大小。段大小可以通过构建
PostgreSQL 时的配置选项
--with-segsize 调整。)
原则上,空闲空间映射和可见性映射 fork 也可能需要多个段,不过实践中
这不太可能发生。
含有可能很大的条目列的表会有一个关联的TOAST表,
用于对大到无法保存在表行本身中的字段值进行行外存储。
pg_class.reltoastrelid
从表链接到它的 TOAST 表(如果有)。
更多信息见 Section 66.2。
表和索引的内容在 Section 66.6 中有进一步 讨论。
表空间使情况变得更复杂。每个用户定义的表空间在
PGDATA/pg_tblspc 目录内都有一个
符号链接,指向该物理表空间目录(即表空间的
CREATE TABLESPACE 命令中指定的位置)。
这个符号链接以表空间的 OID 命名。在物理表空间目录内有一个名称取决于
PostgreSQL 服务器版本的子目录,例如
PG_9.0_201008051。(使用这个子目录的原因是让相继的
数据库版本能够使用相同的 CREATE TABLESPACE 位置值而
不发生冲突。)在这个特定版本的子目录内,对于每个在表空间中拥有元素的
数据库都有一个以其 OID 命名的子目录。表和索引就存储在该目录中,使用
filenode 命名方案。
pg_default 表空间不通过
pg_tblspc 访问,它对应于
PGDATA/base。类似地,
pg_global 表空间不通过
pg_tblspc 访问,它对应于
PGDATA/global。
pg_relation_filepath() 函数显示任何关系的完整路径
(相对于 PGDATA)。作为记忆上述诸多规则的替代,它
通常很有用。但请记住,这个函数只给出关系 main fork 第一个段的名称
— 您可能还需要追加段号和/或 _fsm、
_vm 或 _init 后缀,才能找到与该
关系相关的所有文件。
临时文件(用于排序超出内存容量的数据等操作)创建在
PGDATA/base/pgsql_tmp 中,如果为
它们指定的表空间不是 pg_default,则创建在表空间目录
的 pgsql_tmp 子目录中。
临时文件的名称形如
pgsql_tmp,
其中 PPP.NNNPPP 是所属后端的 PID,
NNN 用于区分该后端的不同临时文件。