PostgreSQL物理存储结构

895 阅读3分钟

数据库一般分为逻辑存储结构和物理存储结构。逻辑存储结构通常指标、索引、视图、函数等逻辑对象,在前文已经对部分逻辑存储结构做了部分介绍,故本章主要介绍物理存储结构。物理存储结构主要是数据库在物理层面上如何存储的。

数据库集簇的布局

使用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值会被一些命令(例如TRUNCATEREINDEXCLUSTER)所改变,所以不能根据表的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