Postgresql 体系架构 - 物理结构
在 PostgreSOL的体系架构中,最重要的组成部分是数据的存储结构,而数据的存储结构分为以下两种。
逻辑存储结构:数据库内部组织和管理数据的方式
物理存储结构:操作系统中组织和管理数据的方式。
PostgreSOL的体系架构如图所示

- 物理结构
1.1. 相关概念
1.1.1. OID
OID(对象标识符)在整个数据库中唯一地标识一个数据库对象,这个数据库对象可以是数据库、表、索引、视图、元组、类型等,保存在无符号四字节的整形变量中。所有数据库对象各自对应一个OID。
对象标识符(oid)在PostgreSQL内部用作各种系统表的主键。类型oid表示对象标识符。oid还有几个别名类型,每个都命名regsomething。
oid类型目前实现为无符号四字节整数。因此,它并不大足以在大型数据库甚至大型单个表中提供数据库范围内的惟一性。oid类型本身除了比较之外几乎没有什么操作。但是,它可以被强制转换为整数,并且然后使用标准整数运算符进行操作。除了专门的输入和输出例程外,OID别名类型没有自己的操作。
这些例程能够接受并显示系统对象的符号名称,而不是原始的类型oid将使用的数值。别名类型允许简化对OID值的查找对象。例如,要检查与表mytable相关的pg_attribute行
SELECT * FROM pg_attribute WHERE attrelid = 'mytable'::regclass;
更胜于使用:
SELECT * FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'mytable');

虽然一个表的文件节点通常和它的 OID相匹配; 但实际上也没必要如此,如ALTER TABLE, TRUNCATE, REINDEX, CLUSTER等操作,可以改变文件节点而同时保留相匹配,但实际上并不必 TRUNCATE、REINDEX、CLUSTER以及某些形式 OID。避免假设该文件节点和表OID相同。同样,对于某些系统目录,包括pg_class本身,pg_class.Relfilenode包含零。这些目录的实际文件编号为存储在较低级别的数据结构中,可以使用pg_relation_filen ode()函数获取。
1.1.2 relfilenode
在PostgreSQL中,relfilenode是一个对象(比如表、索引、序列等)在文件系统上的物理存储文件的编号。
在表或者索引超过 1GB 之后,它就被划分成1G大小的段。 第一个段的文件名和文件节点相同;随后的段被命名为 filenode.1、filenode.2等等。这样的安排避免了在某些有文件大 小限制的平台上的问题(实际上,1GB只是默认的段尺寸。段尺寸可以在编译PostgreSQL时 使用配置选项--with-segsize进行调整)。原则上,空闲空间映射和可见性映射分支也可以要求多个段,但实际上这很少发生。 如果一个表的列中可能存储相当大的项,那么该表就会有个与之相关联的TOAST表, 它用于 存储无法保留在在表行中的域值的线外存储。
该文件有1G的大小限制,超过1G或生成新的文件(文件名后边加数字编号);
relfilenode标识对象物理位置的数字标号,会随数据存放的变化位置变化而变化;
函数pg_relation_filenode() 可以获得对象的relfilenode;
postgres=# select pg_relation_filenode('test');

postgres=# truncate table test;
postgres=# select pg_relation_filenode('test');

truncate之后,t2表的relfilenode从16388变为了16391.
通过pg_relation_filenode()可以将oid转化为relfilenode,
通过pg_filenode_relation可以将relfilenode转化为oid.
使用pg_relation_filenode()永远会得到正确的结果,从pg_class系统表中查询则可能会得到错误的结果。
获得表的oid信息:
postgres=#select oid from pg_class where relname='test';
postgres=#select 'test'::regclass::oid;
先查看数据库的
postgres=# select oid,datname from pg_database;
查找物理文件所在位置:
postgres=#select oid,relfilenode from pg_class where relname='test';
postgres=# select pg_relation_filepath('test');

- 1.3. Relation
关系代表非数据库本身的数据库对象,包括表、视图、索引和toast等,不包括数据库本身。
- 1.4 MVCC
Multi-Version-Concurrency-Control是一种并发控制机制,用于允许一些transactions读取和写入相同的行,而不会因一个进程导致其他进程停顿。在PostgreSQL 中,MVCC是通过在tuples被修改时创建副本(versions)来实现的;在可以看到旧版本终止的事务之后,需要删除那些旧版本。数据库引擎根据不同的事务隔离级别, 通过查询事务快照和事务提交日志来完成元组的可见性检查。
- 1.5. LSN
LSN(Log Sequence Number,日志序列号)是 PostgreSQL 中用于标识数据库操作日志位置的 64 位标识符,是确保数据一致性和完整性的关键。LSN 通常表示为 X/Y 的形式。 其中 X 和 Y 为十六进制数。前 32 位 (X) 表示日志文件的编号,后 32 位 (Y) 表示日志文 件中的偏移量。例如,16/B374D848。每次数据库发生写操作时,PostgreSQL 会在 WAL 日志 中记录这些操作,并分配一个新的 LSN,以便在系统故障后进行恢复。
使用 pg_waldump 打印
[postgres@pgserver01 pg_wal]$ pg_waldump 000000010000000000000001

获取当前的 LSN 值
postgres=# select pg_current_wal_lsn();

从 LSN 计算出 WAL 文件名(注意:timeline 是根据当前实例生成的,不同实例的 timeline 字段计算结果可能不同)
postgres=# select pg_walfile_name('0/17FB7B0');
2. Page结构
据库文件在Linux平台被划分为默认8K固定长度的page进行管理,通过启动参数 BLCKSIZE可以预设page的大小。如果page设低了,相同数据量的文件需要分裂成更多的 page,IO次数和索引分裂次数都会增加,性能会降低较多;如果page设高了,page内部的数据检索效率会降低,性能一样会降低不少,一般来说8K和16K对于数据库系统来说是最优解。
上图为一个page的结构,主要由5个部分组成:

Page Header:为页头,主要存储LSN,page中空闲空间的开始offset和结束offset等。下面再展开讲。
ItemId data:是page中表记录的索引条目。一个索引条目4个字节,由两部分组成:此记录在page中的offset和记录长度length。
Free space:是此page中剩余可用的空间,不算标记为delete后的空间;是指完全没有被使用的空间,也相当于page中没有被分配的空间。
Item:就是指表实际存储的记录。
Special space: 存储索引访问方法(AM: Access Method)信息,不同的索引访问方法,内容不一样。但如果是表的page,那么这里是空的,没有任何信息。
页头部分其实是这个 page 的一些元数据信息,由 PageHeaderData 结构体表示,主要有如下内容:

pd_lsn:xlog(WAL) 在当前 page 的最后一次修改的日志记录
pd_checksum:文件页对应的校验和,保护文件页内容
pd_flags:page 的一些状态信息,取值有如下几种
PD_HAS_FREE_LINES:是否还有未使用的 linp 指针
PD_PAGE_FULL:页面已满,剩余的空间无法容纳新的 Tuple
PD_ALL_VISIBLE:page 所有的 tuple 都是可见的
PD_VALID_FLAG_BITS:全部有效的 pd_flags 标记位
pd_lower:该 page 内空闲空间的起始位置
pd_upper

最低0.47元/天 解锁文章
489

被折叠的 条评论
为什么被折叠?



