数据库集簇的逻辑结构

数据库集簇(database cluster)是指由单个PostgreSQL服务器实例管理的数据库集合。(解读:数据库集簇是集合,其元素是数据库。一个PostgreSQL服务器实例只会在单机上运行并管理单个数据库集簇。注意这里表述中的两个”单“,即单机单个集簇,说明服务器实例不能跨多个主机,不能管理多个数据库集簇)。数据库集簇在本质上就是一个文件目录,其包含着一些列子目录与文件。(例如执行/opt/pgsql/bin/initdb -D /pgdata/10/data -W 在指定目录下创建基础目录,从而初始化一个新的数据库集簇,这里的/pgdata/10/data就是数据库集簇)基础目录文件树见文末。


注:PostgreSQL的数据库集簇(database cluster)概念和高可用数据库集群不同,这里的集簇(cluster)仅表示多个逻辑的数据库在用一个数据库实例中。

逻辑结构

区分数据库和数据库实例:PostgreSQL数据库是由一系列位于文件系统上的物理文件组成(通常这些物理文件被称为数据库);物理文件加上进程管理的内存和管理这些物理文件的进程称为该数据库的实例。在上述初始化数据目录的操作中,initdb工具自动创建了template0、template1和postgres数据库(解读:postgres是默认数据库,template0和template1是生成其他数据库的模板)。一个数据库集簇可以包含多个数据库、多个User,梅特数据库以及数据库中的表、索引等都有它们的拥有者:User。
创建一个Database时会为这个Database创建一个名为public的默认Schema,每个Database可以多个Schema,在数据库中创建表、索引等时如果没有指定Schema,都会在public这个Schema中。(解读:Schema可以理解为一个数据库中的命名空间,在数据库中创建的所有对象都在Schema中创建,一个用户可以从同一个客户端连接中访问不同的Schema)。不同的Schema中可以有多个相同名称的表、索引、视图等。

数据库对象

数据库是数据库对象(database object)的集合(例如,索引、视图、函数等都是数据库对象)。在PostgreSQL中,数据库本身也是数据库对象,并在逻辑上彼此分离。除数据库之外的其他数据库对象(如表、索引等)都归属于各自相应的数据库。虽然隶属于同一个数据库集簇,但无法直接从集簇中的一个数据库访问到。

表空间也是数据库对象,在PostgreSQL中最大的逻辑存储单元就是表空间。数据库中创建的对象,包括数据库本身都保存在表空间中(例如表、索引和整个数据库)。在创建数据库对象时,可以指定数据库对象的表空间,如果不指定则使用默认表空间。初始化数据库目录时会自动创建pg_default和pg_global两个表空间。

  • pg_global表空间的物理文件位置在数据目录的global目录中,它用来保存系统表。
  • pg_default表空间的物理文件位置在数据目录中的base目录,是template0和template1数据库的默认表空间。创建数据库时,默认从template1数据库进行克隆。因此除非特别指定新建数据库的表空间,默认使用template1的表空间。
    在PostgreSQL内部,所有数据库对象都通过相应的对象标识符(object identifier, oid)进行管理,这些标识符是无符号的4字节整型。数据库对象和各个oid之间的关系存储在适当的系统目录中,具体取决于对象的类型。
  • 数据库的oid存储在pg_database系统表中。
  • 数据库中的表、索引、序列等对象的oid存储在pg_class系统表中。


从base文件目录下可以看到template0、template1和postgres对应的oid文件,也即相应的数据库文件。

pg_class系统表的oid为1259,它位于base目录postgres目录下,处于pg_default表空间中。

pg_database系统表的oid为1262,它位于global目录下,处于pg_global表空间中。



pg_default表空间的oid为1663,但是没有找到以1663命名的文件夹。


pg_global表空间的oid为1664,但是没有找到以1664命名的文件夹。

OID通常是从1开始分配,但在初始化数据集簇时,会先将一部分OID分配给系统表、系统表元祖、系统表上的索引等数据库对象,这一部分OID可以在系统表所对应的头文件中找到。同时,为了给后续版本留下扩展的余地,初始化数据集簇时还会预留一部分OID资源。这样,在系统运行时可分配的OID资源实际是从16384开始的。在PostgreSQL源代码src/include/catalog子目录下有一个shell脚本unused_oids用来输出当前版本中预分配和预留的OID的使用情况。

对于用户表的元祖,是可以在创建用户表时选择是否具有OID属性的。如果在CREATE TABLE语句中使用了WITH OIDS选项,则该用户表中插入的每一个元祖都将被分配一个OID。否则,默认状态下用户表的元祖是没有OID属性的。

OID的分配由系统中的一个全局OID计数器来实现,每次需要分配新的OID时,就从该计数器中取当前的OID,然后该计数器将会加1。OID分配时会采用互斥锁加以锁定以避免多个要求分配OID的请求获得同一个OID。

数据库的布局

如下图所示,一个数据库与base子目录下的一个子目录对应,且该子目录的名称与相应数据库的oid相同。例如,当数据库sampledb的oid为16384时,它对应的子目录名称就是16384。数据库中的每个表和索引都至少在相应子目录下存储为一个文件。

表空间的布局

PostgreSQL中的表空间对应一个包含基础目录之外数据的目录(附加数据区域)。执行CREATE TABLESPACE语句会在指定目录下创建表空间。在该目录下还会创建版本特定的子目录(PG_主版本号_目录版本号)。每个用户定义的表空间在PGDATA/pg_tblspc目录里面都有一个符号链接,它指向表空间的物理目录,该符号链接用表空间的OID命名。系统默认创建的表空间pg_default和pg_global并没有通过符号链接的方式指向其物理目录,而是直接对应PGDATA/base和PGDATA/global。


如果在mytblspc下创建新表,但新表所属的数据库却创建在基础目录下,那么PG会首先在版本特定的子目录下创建名称与现有数据库oid相同的新目录,然后将新表文件放置在刚创建的目录下。如下图Database Directory所指示的一样。

数据目录结构


/pgdata/10/data

|— PG_VERSION PostgreSQL主版本号文件

|— postgresql.conf 全局配置文件,除认证外其他行为由其配置

|— postgresql.auto.conf 只保存ALTER SYSTEM命令修改的参数

|— pg_hba.conf 全局配置文件,负责客户端的连接和认证配置

|— pg_ident.conf 控制PostgreSQL用户名映射

|— base

      |--- 1                                template1数据库目录|--- 13213                        template0数据库目录|--- 13214                        postgres数据库目录





|— pg_serial 包含已提交的可序列化事务信息的子目录,初始化后为空目录

|— pg_tblspc 包含指向表空间的符号链接的子目录,初始化后为空目录

|— global 包含集簇范围的表的子目录,比如pg_database

|— pg_logical 包含用于逻辑复制的状态数据的子目录

|— pg_snapshots 包含导出的快照的子目录

 |---  pg_twophase                   用于预备事务状态文件的子目录|---  pg_commit_ts                  事务提交的时间戳数据|---  pg_multixact                     多事务状态数据


|— pg_stat 统计子系统的永久文件

|---  pg_dynshmem                  动态共享内存子系统中使用的文件|---  pg_notify                           LISTEN/NOTIFY状态数据


|— pg_stat_tmp 统计子系统的临时文件

|— pg_wal WAL段文件,从pg_xlog重命名而来


|— pg_replslot 复制槽数据

|---  pg_subtrans                        子事务状态数据


|— pg_xact 事务提交状态数据,从pg_clog重命名而来

数据库集簇的物理结构

每个表和索引都存储在其所属数据库目录下的独立文件里,以该表或者该索引的filenode号命名,该号码记录在该表或索引在系统表pg_class中对应元祖的relfilenode属性中。在表或索引超过1GB之后,它就被分裂成多个1GB大小的段。第一个段的文件名和filenode相同,随后的段命名为filemode.1,filenode.2 …这样的策略避免了在某些有文件大小限制的平台上可能出现的问题。如果一个表的有些属性要存储相当大的数据,那么就会有个与之相关联的TOAST表,用于存储无法在数据行中放置的超大外置数据。表对应的pg_class元祖的reltoastrelid属性记录了她的TOAST表OID。

表和元组的组织方式:在PG中,同一个表中的元组按照创建顺序依次插入到表文件中,元组之间不进行关联,这样的表文件称为堆文件。PG系统中包含了四种堆文件:普通堆(ordinary cataloged heap)、临时堆(temporary heap)、序列(SEQUENCE relation,一种特殊的单行表)和TOAST表(TOAST table)。临时堆的结构与普通堆相同,但临时堆仅在会话过程中临时创建,会话结束会自动删除。序列则是一种元组值自动增加的特殊堆。TOAST表其实也是一种普通堆,但是它被专门用于存储变长数据。尽管这几种堆文件功能各异,但在底层的文件结构却是相似的。每个堆文件都是由多个文件块组成。数据的读写是以块为单位,块默认大小为8K,在编译PG时指定的BLCKSZ决定块的大小。

文件块在物理磁盘上的存储形式如下。Page Header Data是长度为20字节的页头数据,包含该文件块的一般信息,如空闲空间的起始和结束位置、Special space的开始位置、项指针的开始位置、标志信息,如是否存在空闲项指针、是否所有的元组都可见。


Linp是ItemIdData类型的数组,ItemIdData类型由lp_off、lp_flags和lp_len三个属性组成。每个ItemIdDate结构用来指向文件块中的一个元组,其中lp_off是元组在文件块中的偏移量,而lp_len则说明了该元组的长度,lp_flags表示元组的状态(分为未使用、正常使用、HOT重定向和死亡四种状态)。每个Linp数组元素的长度为4字节。

Freespace是指未分配的空间(空闲空间),新插入页面中的元组及其对应的Linp元素都将从这部分空间中来分配,其中Linp元素从Freespace的开头开始分配,而新元组数据则从尾部开始分配。

Special space是特殊空间。用于存放与索引方法相关的特定数据,不同的索引方法在Special space中存放不同的数据。由于索引文件的文件块结构和普通表文件的相同,因此Special space在普通表文件块中并没有使用,其内容被置为空。

参考:
PostgreSQL实战

PostgreSQL数据库集簇相关推荐

  1. PostgreSQL流复制之二:pgpool-II实现PostgreSQL数据库集群(转发+整理)

    转发来源: PostgreSQL的集群技术比较:https://iwin.iteye.com/blog/2108807 参考:https://blog.csdn.net/yaoqiancuo3276/ ...

  2. k8s集群下创建高可用postgresql数据库集群实践

    K8s 安装 pg集群服务器 主要的目的是做到自动灾备切换,利用kubernetes 集群做到高可用的数据库服务. 三个节点, 2节点部署 proxy,sentinel,3节点keeper (DB) ...

  3. PostgreSQL数据库存储结构

    表空间---数据库---数据库对象 数据库初始化之后就会有pg_default和pg_global两个表空间(pg_tablespace视图查看,也可以通过\db查看). pg_default表空间是 ...

  4. PostgreSQL数据库中的角色(Role)、用户(User)、模式(Schema)

    文章目录 PostgreSQL数据库中的角色(Role).用户(User).模式(Schema) 角色(Role)和用户(User) 角色操作 CREATE ROLE 创建角色 ALTER ROLE修 ...

  5. Debezium系列之:使用Debezium接入PostgreSQL数据库数据到Kafka集群的详细技术文档

    Debezium系列之:使用Debezium接入PostgreSQL数据库数据到Kafka集群的详细技术文档 一.概述 二.连接器的工作原理 1.安全 2.快照 3.Ad hoc snapshots ...

  6. postgresql数据库使用Citus实现集群

    citus是PostgreSQL数据库中的一种轻量级的分库分表解决方案.citus不是一个单独的程序,它是PostgreSQL数据库中的一个插件,可以使用create extension安装此插件.  ...

  7. 数据库服务器 之 PostgreSQL数据库的日常维护工作

    来自:LinuxSir.Org 摘要:为了保持所安装的 PostgreSQL 服务器平稳运行, 我们必须做一些日常性的维护工作.我们在这里讨论的这些工作都是经常重复的事情, 可以很容易地使用标准的 U ...

  8. postgresql 数据库 客户端认证

    简介 当客户端与数据库服务器连接时,它需要指定用哪个数据库用户的身份来连接. PostgreSQL 为我们提供了很多种客户端认证的方式,我们可以根据自己的需要来选择认证方式. psql psql 是 ...

  9. postgresql数据库的备份与恢复

    和任何包含珍贵数据的东西一样,PostgreSQL 数据库也应该经常备份.尽管这个过程相当简单, 但是我们还是应该理解做这件事所用的一些技巧和假设. 备份 PostgreSQL 数据有三种完全不同的方 ...

最新文章

  1. 2009年国内十强开源CMS排行榜[转]
  2. JVM 有 Full GC,为什么还会出现 OutOfMemoryError呢?
  3. 如何设计网站导航更利于SEO优化?
  4. python 循环添加array_Python的备忘细节小抄
  5. 零拷贝概念 -- linux内核
  6. 9008刷机怎么刷_OV快捷进入高通进9008或fastboot模式刷机解锁,和MTK关机解锁
  7. 计算机电子电路技术 电路与模拟电子部分,[高等教育]计算机电子电路技术--电路与模拟电子部分直流电源.ppt...
  8. Cisco 2960密码恢复
  9. citrix4.5无法进入发布程序界面The supplied credentials could not be validated
  10. laravel如何利用数据库的形式发送通知
  11. java基础代码详解
  12. 清华大学计算机直硕生,推免数据 | 清华大学计算机系三大巨变——直硕生减半,本校增多,211增多...
  13. 队列与栈的原理及特点
  14. 名词性从句引导词的基本用法
  15. linux查找外接摄像头端口
  16. bus error的解决方法
  17. vscode如何打开html
  18. 网络安全笔记-99-渗透-渗透测试方法论
  19. 天猫精灵--智能家居接入(一)
  20. 高新技术企业申报材料汇编

热门文章

  1. Ubuntu安装Flash Player插件
  2. LSTM内部结构及前向传播原理——LSTM从零实现系列(1)
  3. 基于MVC模式的用户登录
  4. 服务器安全狗V4.0.05932 小版本更新
  5. 杭电操作系统实验一----Linux内核编译及添加系统调用(完整实验报告)
  6. rand()函数100000随机数_随机函数Rand、Randbetween应用技巧解读
  7. 如何设计一个“好的”测试用例
  8. 游戏开发第一阶段笔记(3):C语言 指针与数组
  9. 分享怎样快速阅读的5大方法
  10. android播放网络音频