数据库一般分为逻辑存储结构和物理存储结构。逻辑存储结构通常指标、索引、视图、函数等逻辑对象,在前文已经对部分逻辑存储结构做了部分介绍,故本章主要介绍物理存储结构。物理存储结构主要是数据库在物理层面上如何存储的。
数据库集簇的布局
使用initdb命令初始化目录,初始化完成后,目录下存在如下6个配置文件:
postgresql.conf:数据库实例的配置文件,基本所有参数在此文件中配置,配置文件若有多个相同参数配置,则最后一个参数配置生效。
postgresql.auto.conf:使用ALTER SYSTEM修改的配置参数存储在该文件中,该配置文件优先于postgresql.conf,则两个配置文件中有同一个参数配置,优先取该配置文件的。
pg_ident.conf:ident认证方式的用户映射文件,控制PostgreSQL用户名映射
pg_hba.conf:认证配置文件,用于配置允许哪些IP的主机访问数据库、认证的方式是什么等信息(搭建流复制也需要配置该文件)。
PG_VERSION:存储PostgreSQL主版本号。
postmaster.opts:记录服务器上次启动的命令行参数。
此上述6个配置文件外,此目录下还会生成如下子目录
| 子目录 | 描述 |
|---|---|
base/ | 每个数据库对应的子目录存储于此,默认表空间目录 |
global/ | 一些共享系统表的目录。数据库集簇范畴的表(例如pg_database),以及pg_control文件。 |
log | 程序日志目录。 |
pg_commit_ts/ | 事务提交的时间戳数据(9.5及更新版本)。 |
pg_xact/ | 事务提交状态数据,在版本(9.6及更老版本)中被为pg_clog。 |
pg_dynshmem/ | 动态共享内存子系统中使用的文件(9.4或更新版本)。 |
pg_logical/ | 逻辑复制的状态数据(9.4或更新版本)。 |
pg_multixact/ | 多事务状态数据 |
pg_notify/ | LISTEN/NOTIFY状态数据 |
pg_repslot/ | 复制槽数据(9.4或更新版本)。 |
pg_serial/ | 已提交的可串行化事务相关信息(9.1或更新版本) |
pg_snapshots/ | PostgreSQL函数pg_export_snapshot在导出的快照信息文件(9.2或更新版本)。 |
pg_stat/ | 统计子系统的永久文件 |
pg_stat_tmp/ | 统计子系统的临时文件 |
pg_subtrans/ | 子事务状态数据 |
pg_tblspc/ | 存储指向各个用户自建表空间实际目录的链接文件 |
pg_twophase/ | 两阶段事务(prepared transactions)的状态文件 |
pg_wal/ | WAL( Write Ahead Logging)日志目录,从pg_xlog重命名而来。 |
database布局
base目录下存在许多子目录,一个子目录同一个数据库对应,该子目录的名称与相应数据库的OID相同。
postgres=# select oid,datname from pg_database;
oid | datname
-------+-----------
13593 | postgres
1 | template1
13592 | template0
16745 | test
(4 rows)
postgres=# show data_directory;
data_directory
-----------------------
/opt/pgsql/bin/./data
(1 row)
postgres=# \! ls /opt/pgsql/bin/./data/base
1 13592 13593 16745 pgsql_tmp
表、索引的布局
postgres数据库对应的目录为13593,在这个目录下存放着该数据库下的表、索引等文件,每个表和索引都会分配一个文件号relfilenode,数据文件格式以"relfilenode.顺序号"命名,每个小于1GB的表或索引都在相应的数据库目录中存储为单个文件,大于1GB时,就会从1开始生产顺序号。可以通过如下方式查找表或者索引对应的物理文件
postgres=# \d
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------
public | test | table | postgres
(1 row)
postgres=# select relnamespace,relname,relfilenode from pg_class where relname='test';
relnamespace | relname | relfilenode
--------------+---------+-------------
2200 | test | 16737
(1 row)
该表的relfilenode为16737,所以对应的物理文件为"$PGDATA/base/13593/16737",也可以通过命令直接获取该表的物理文件
postgres=# select * from pg_relation_filepath('test');
pg_relation_filepath
----------------------
base/13593/16737
(1 row)
注意,表和索引的relfilenode值通常与其OID一致,但也存在例外,表和索引的relfilenode值会被一些命令(例如TRUNCATE,REINDEX,CLUSTER)所改变,所以不能根据表的oid来判断文件物理文件。见下例:
postgres=# select oid,relnamespace,relname,relfilenode from pg_class where relname='test';
oid | relnamespace | relname | relfilenode
-------+--------------+---------+-------------
16737 | 2200 | test | 16737
(1 row)
postgres=# truncate test;
TRUNCATE TABLE
postgres=# select oid,relnamespace,relname,relfilenode from pg_class where relname='test';
oid | relnamespace | relname | relfilenode
-------+--------------+---------+-------------
16737 | 2200 | test | 16746
(1 row)
postgres=# select * from pg_relation_filepath('test');
pg_relation_filepath
----------------------
base/13593/16746
(1 row)
对表truncate前,表的oid即relfilenode均为16737,truncate后,relfilenode变为16746。
另外,一般表都有两个与之相关联的文件,后缀分别为_fsm和_vm。这些实际上是空闲空间映射(free space map) 和可见性映射(visibility map) 文件,分别存储了表文件每个页面上的空闲空间信息与可见性信息。索引没有可见性映射文件,只有空闲空间映射文件。
表空间的目录
使用CREATE TABLESPACE语句会在指定的目录下生产带有CATALOG VERSION的子目录
postgres=# \! ls /opt/pgsql/bin/tbs
PG_12_201909212
12代表大版本,201909212为Catalog version
[postgres@VM-0-11-centos bin]$ ./pg_controldata -D ./data | grep Catalog
Catalog version number: 201909212
在表空间创建表,查询其物理文件位置:
postgres=# create table test(a int, b text) tablespace tbs;
CREATE TABLE
postgres=# select * from pg_relation_filepath('test');
pg_relation_filepath
---------------------------------------------
pg_tblspc/16515/PG_12_201909212/13593/16756
(1 row)
[postgres@VM-0-11-centos bin]$ ls -l ./data/pg_tblspc/16515
lrwxrwxrwx 1 postgres postgres 18 Dec 12 09:08 ./data/pg_tblspc/16515 -> /opt/pgsql/bin/tbs