Chapter 50. 数据库物理存储

Table of Contents
50.1. 数据库文件布局
50.2. TOAST
50.3. 数据库分页文件

本章对 PostgreSQL 数据库使用的物理格式进行一个概述。

50.1. 数据库文件布局

本节在文件和目录的层次上描述存储格式。

数据库集群所需要的所有数据都存储在集群的数据目录里, 通常用 PGDATA 来引用(用的是可以定义之的环境变量的名字)。 PGDATA 的一个常见位置是 /var/lib/pgsql/data。 不同 postmaster 管理的多个集群,可以在同一台机器上共存。

PGDATA 目录包含几个子目录以及一些控制文件, 在 Table 50-1 里面显示。除了这些必要的东西之外, 集群的配置文件 postgresql.confpg_hba.conf, 和 pg_ident.conf 通常都存储在 PGDATA (不过从 PostgreSQL 8.0 开始以上的版本,我们可以把它们放在别的地方。)

Table 50-1. PGDATA的内容

描述
PG_VERSION一个包含 PostgreSQL 主版本号的文件
base包含每个数据库对应的子目录的子目录
global包含集群范围的表的子目录,比如pg_database
pg_clog包含事务提交状态数据的子目录
pg_multixact包含多重事务(multi-transaction)状态数据的子目录(用于共享的行锁)
pg_subtrans包含子事务状态数据的子目录
pg_tblspc包含指向表空间的符号链接的子目录
pg_twophase包含用于准备好事务状态文件的子目录
pg_xlog包含 WAL (预写日志)文件的子目录
postmaster.opts一个记录 postmaster 最后一次启动时使用的命令行参数的文件
postmaster.pid一个锁文件,记录着当前的 postmaster PID 和共享内存段 ID (在 postmaster 关闭之后不存在)

对于集群里的每个数据库,在 PGDATA/base 里都有一个子目录对应, 子目录的名字是该数据库在 pg_database 里的 OID。 这个子目录是该数据库文件的缺省位置;特别值得一提的是,该数据库的系统表存储在此。

每个表和索引都存储在独立的文件里,以该表或者该索引的 filenode 号命名, 我们可以在 pg_class.relfilenode 找到。

Caution

请注意,虽然一个表的 filenode 通常和它的 OID 相同,但实际上并不必须如此; 有些操作,比如 TRUNCATEREINDEXCLUSTER 以及一些特殊的 ALTER TABLE 形式,都可以改变 filenode 而同时保留 OID。 我们不应该假设 filenode 和表 OID 相同。

在表或者索引超过 1Gb 之后,它就被分裂成一 G 大小的。 第一个段的文件名和 filenode 相同;随后的段名名为 filenode.1,filenode.2,等等。 这样的安排避免了在某些有文件大小限制的平台上的问题。表和索引的内容在 Section 50.3 里有进一步讨论。

一个表如果有些字段里面可能存储相当大的数据,那么就会有个相关联的 TOAST 表, 用于存储无法在表的数据行中放下的太大的线外数据。 如果有的话,pg_class.reltoastrelid 从一个表链接到它的 TOAST 表。 参阅 Section 50.2 获取更多信息。

表空间把情况搞得更复杂些。每个用户定义的表空间都在 PGDATA/pg_tblspc 目录里面有一个符号连接,它指向物理的表空间目录(就是在 CREATE TABLESPACE 命令里声明的那个目录)。这个符号连接是用表空间的 OID 命名的。 在物理表空间里面包含多个子目录,每个子目录对应着一个在这个表空间里有元素的数据库,并且该子目录以那个数据库的 OID 命名 该目录里的表遵循 filenode 的命名规则。 pg_default 没有通过 pg_tblspc 关联,但是对应 PGDATA/base。 类似的还有,pg_global 没有通过 pg_tblspc 关联,而是对应 PGDATA/global