文章目录
- Pg是一种运行在各种平台上的免费的开源的对象关系数据库,
- 以关系数据库和SQL为基础,
- 扩展了抽象数据类型,从而具备面向对象特性的数据库。
- Pg由连接管理系统(系统控制器)、编译执行、存储管理、事务、系统表五部组成,图2-1。
- 连接管理
- 接受外部操作对系统的请求,
- 对操作请求进行预处理和分发,起系统逻辑控制作用
- 编译执行由
- 查询编译器、查询执行器,
- 完成操作请求在数据库中的分析处理和转化工作,
- 最终实现物理存储介质中数据的操作;
- 存储管理由索引管理器、内存管理器、外存管理器,
- 负责存储和管理物理数据,
- 提供对编译查询系统的支持;
- 事务系统由事务管理器、日志管理器、并发控制、锁管理器组成,
- 日志管理器和事务管理器完成对操作请求处理的事务一致性支持,锁管理器和并发控制提供对并发访问数
据的一致性支持;
- 日志管理器和事务管理器完成对操作请求处理的事务一致性支持,锁管理器和并发控制提供对并发访问数
- 系统表是Pg数据库的元信息管理中心
- 包括数据库对象信息和数据库管理控制信息。
- 系统表管理元数据信息,将Pg的各个模块有机连接,形成一个高效的数据管理系统。
2.1系统表
- 关系数据库中,为实现数据库系统的控制,须提供数据字典的功能。
- 数据字典存储各种对象的描述信息,且存储系统管理所需的各种对象的细节信息。
- 内容来看,数据字典包含数据库系统中所有对象及其属性的描述信息、对象之间关系的描述信息、对象属性的自然语言含义及数据字典变化的历史(即数据库的状态信息)。
- 数据字典是关系数据库系统管理控制信息的核心,在Pg数据库系统中,系统表扮演着数据字典的角色。
- 系统表是Pg存放结构元数据的地方
- 它在Pg中表现为存放有系统信息的普通表或者视图。
- 用户可以删除然后重建这些表、加列、插人和更新数值,
- 用户去修改系统会导致系统信息的不一致性,导致系统紊乱。
- 用户不手工修改系统表,
- 而由SQL命令关联的系统表操作自动维护系统表信息。
- 创建数据库语句会向pg_database表插一行,
- 并在磁盘上创建该数据库。
- Postgresql的每一个数据库中都有自己的一套系统表,其中大多数系统表都是在数据库创建时从模板数据库中拷贝过来的,因此这些系统表里的数据都是与所属数据库相关的。
- 只有少数系统表是所有数据库共享的(比如pg_ database),这些系统表里的数据是关于所有数据库的。
- 系统表保存了数据库的所有元数据,
- 所以对系统表的访问是非常频繁的。
- 为提高系统性能,在内存中建立了共享的系统表CACHE,用Hash函数和Hash表提高查询效率,
- 这些内容将在第3章详细介绍。
- 系统表功能的实现代码包含系统表定义文件和系统表绑定函数实现文件。
- src/include/catalog有若干个“pg_xxx”的.h文件,
- 定义了名为pg_xx的系统表的数据结构,
- indexing.h文件定义了所有的系统表索引,
- toasting.h定义所有系统表的TOAST表(TOAST表用于存放普通表中的超长属性值,3章介绍)
- src/ backend/ catalog的 pg_xxx.c中定义了对Pg_xx进行相关操作的函数,
- indexing.c定义了四个操作系统表索引的函数,
- toasting. c文件定义了四个操作系统表的T0AST表的函数。
2.1.1主要系统表功能及依赖关系
- 8.4.1中,有42张系统表和17张系统视图,
- 系统视图是建立在基本系统表之上。
- 本节将对主要的系统表进行介绍,其他系统表将在后续章节中分别予以介绍
1 pg_namespace
- pg_namespace存储命名空间。
- 命名空间是SQL92模式下层的结构:
- 每个名字空间有独立的关系、类型等集合,但不相互冲突。
- Postgresql的名字空间层次是:数据库.模式 表,属性。
- 要访问一个对象时, 按以下名字空间顺序搜索
- 特殊名字空间( special),仅用于创建模式。
- 临时表的名字空间(TEMP)。
- 系统表的名字空间。
- pg_namespace中每个元组对应一名字空间
- 每一个名字空间都被分配一个OID,
- 用于在整个数据库系统中唯一地标识一个数据库对象,
- 包括数据库、表、视图、索引等,
- 在2.2节中会进一步介绍)
- 且存储在对应元组的隐藏属性(Pg中每个元组都有用户不可见的属性,用于记录系统信息)
- 每一个名字空间都被分配一个OID,
- 每个元组(名字空间)的属性如2-1
2. pg_tablespace
- 存储表空间信息,将表放置在不同的表空间有助于实施磁盘文件布局。
- Pg_tablespace在整个数据集簇里只有一份,
- 也就是说同一个数据集簇内的所有数据库共享一个
- Postgresql里的表空间允许数据库管理员在文件系统里定义代表数据库对象的文件的存放位置。
- 通过使用表空间,管理员可以控制一个 Postgresql中数据的磁盘布局,即可以通过表空间将Postgresql系统的数据分布在不同的磁盘位置上。
- 有两用处。
- 一,如果初始的集簇所在的分区或者卷用光了空间问,
- 而又无法扩展该分区或卷的空间,
- 那么可以通过表空间去利用另一个分区的空间;
- 二,表空间允许管理员根据数据库对象的使用模式安排数据位置,从而优化性能。
- 一个使用很频繁的索引可放在非常快并且可靠的磁盘上(如一种非常贵的固态设备)。
- 而一个存储归档的数据、很少使用的或者对性能要求不高的表可以存储在一个相对便宜但速度比较慢的磁盘系统上。
- pg-tablespace中每元组都对应一个表空间,
- 每一个表空间都被分配一OID
- 存储在对应元组的隐藏属性
- 每个元组(表空间)含的属性如表2-2
3. pg_database
- 中存放了数据集簇中数据库的信息,
- 也是一个在整个集簇范围内共享的系统表。
- 该表中每一个元组就表示集簇中的一个数据库,每一个数据库都被分配一个OID,并且存储在对应元组的隐藏属性中。
- 每个元组(数据库)包含的属性如表2-3
4. pg_class
- 存储表及
- 与表类似结构的数据库对象信息,
- 含索引、序列、视图、复合数据类型TOAST表
- 与表类似结构的数据库对象信息,
- 每个对象都在pg_class中表示为一个元组,
- 每一个对象都会被分配一个OID
- 作为该元组的一个隐藏属性存
5 pg_type
- 存储数据类型
- 基本数据类型和枚举类型由CREATE TYPE创建,
- 域类型由CREATE DOMAIN创建,
- 复合数据类型在表创建时自动创建。
- pg_type中每一个元组对应一个数据类型,
- 属性如表2-5
6. pg_attribute
- 存储表的属性信息,表的每个属性都有一个元组。
- Pg_ attribute中每个元组(属性)包含的属性如表2-6
7. pg_index
- 存储索引的具体信息,
- 元组包含的属性见表2-7。
- 关键系统表之间存在的相互依赖关系,如图2-2
2.1.2系统视图
- Pg还提供一系列内置的视图,
- 这些视图也是在初始化数据库集簇的时候读取脚本创建的。
- 系统视图提供了查询系统表和访问数据库内部状态的方法。
- 表2-8列出部分系统视图及其用途。
- 系统表是Pg运行控制信息的来源,是数据库系统的核心组成部分。
- 虽然用户可以操作,但为维护系统表信息的一致性,系统表将由系统统一维护。
- 在 Postgresql数据库安装完后,
- 要先进行初始化数据库操作(initdb),
- 生成模板数据库和相应的目录、文件信息,
- 系统表即在此阶段生成。
- 用户数据库及其系统表都从模板数据库进行复制。
- 初始化数据库的过程将在下节详细介绍。
2.2数据集簇
- Pg安装后,
- 做任何事情前,须先initdb初始化磁盘上的数据存储区
- 即数据集簇
- pg管理的用户数据库及系统数据库总称数据集簇
- 做任何事情前,须先initdb初始化磁盘上的数据存储区
- Pg实现中,数据库就是磁盘上一些文件的集合,
- 不过这些文件有特定的文件名、存储位置,
- 且有些文件之间会相互关联。
- 默认情况, Pg的所有数据都存储在其数据目录里
- 常用环境变量PGDATA引用
- 后文中用PGDATA来指代数据目录
- OID用来在整个数据集簇中唯一地标识一个数据库对象,
- 可以是数据库、表、索引、视图、元组、类型
- Pg提供Oid类型表示
- 是无符号整
- OID从1,但初始化数据集簇时,会将一部分OID给系统表、系统表元组、系统表上的索引等数据库对象
- 这一部分OID在系统表对应的头文件。
- 为后续版本留扩展,初始化数据集簇时还预留一部分OID
- 系统运行时可分配的OID实际从16384
- sre/ include/cataog下有个shell脚本 unused oids
- 输出当前版本中预分配和预留的OID的情况。
- 数据集簇中的每一个数据库都对应于系统表 pg_database中的一个元组,该元组OID属性中记录的就是分配给该数据库的OID。
- 同样,对于数据库中的对象如表、索引、视图、类型等,也对应于系统表pg_clas中的一个元组(包括pg_ class本身),这个元组的OID属性中记录的
이ID也就是该对象所分配的OID。
- 对于用户表的元组,可在创建用户表时选择是否具有OD属性。
- CREATETABLE语句中使用 WITH OIDS选项,
- 则表中插入的每一个元组都将被分配一个OID。
- 否则,默认状态下用户表的元组是没有OID属性的。
- OID的分配由系统中的一个全局OID计数器来实现,
- 每次分配新的OID时,就从该计数器中取出当前的OID,然后该计数器将加1。
- 分配时用互斥锁加以锁定
- 避免多个要求分配OID的请求获得同一个OID。
- 初始化数据集簇
- 包括创建包含数据库系统所有数据的数据目录、创建共享的系统表、创建其他的配置文件和控制文件,并创建三个数据库;
- 模板数据库template1和 template0、默认的用户数据库 postgres。
- 以后用户创建一个新数据库时, template1数据库里的所有内容(包括系统表文件)都会拷贝,因此,任何在 template里面安装的内容都自动拷贝到之后创建的数据库中。
- template0和 postgres都是通过拷贝template创建
- 对某个具体的数据库,PGDATA/base里都对应一个子目录,
- 子目录的名字是该数据库在系统表pg_ database里的OID。
- 每个表和索引都存在其所属数据库目录下的独立文件里,
- 以该表或者该索引的flexode号命名,
- 记录在该表或索引在系统表pg_class中对应元组的 relfilenode属性
- 表或索引超1G后,就分裂成多个1GB大小的段。
- 第一个段的文件名和fillenode相同,随后的段命名为
- flexode.1, fillenode.2……
- 这避免了在某些有文件大小限制的平台上可能出现的问题。
- 如果一个表的有些属性要存储相当大的数据,
- 就有个与之相关联的TOAST表
- 用于存储无法在数据行中放置的超大外置数据。
- 表对应的pg_class元组的reltoastrelid属性记录它的TOAST表OID
- Pg默认将数据文件放在PGDATA指定目录下,
- PGDATA所在磁盘空间不足或出于磁盘性能的考虑,
- 要为系统增加新物理存储位置(如在另外一个磁盘上的目录),
- 则可用“表空间”扩展。
- 表空间物理意义上是新的磁盘目录(这个目录可以和PGDATA同处一磁盘或不同磁盘),
- 指定放在表空间中的数据库对象的物理文件
- 都存放在表空间对应目录
- 如果某数据库中的数据库对象被指定放在一个表空间
- 那么在表空间的目录中会以该数据库的OID为名称创一目录,
- 该数据库中属于该表空间的对象的物理文件都放这个目录
- 每个用户定义的表空间在PGDATA/pg_bsp目录里都有符号链接,
- 它指向表空间的物理目录,该符号链接用表空间的OID命名。
- 系统默认创建的表空间pg_default和pg _global并没通过符号链接的方式指向其物理目录,而直接对应PGDATA/base和 PGDATA/global
- PGDATA还保存有数据集簇的配置文件和其他子目录,
- 各子目录及文件的用途说明参见表2-9。
2.2.1
- initdb是在Postgres SQL之前用于初始化数据集簇
- 创数据库目录、系统表、模板数据库
- initdb把指定的选项换成对应参数,
- 通过外部程序调用的方式执行postgres程序
- postgres程序在这种方式下将进入 bootstrap模式创建数据集簇,
- 并读取后端接口postgres.bki来创建模板数据库。
- 下面介绍 postgres.bki文件,
- 然后介绍 bootstrap模式的运行机制。
2. 2. 2 postgres bki
- 后端接口postgres.bki文件
- 编译时由/src/backend/ catalog下的脚本程序genbki.sh读/src/include/catalog下的以.h结尾的系统表定义文件(包括系统表索引和 TOAST表定义文件)创建
- 常放在安装树的share目录。
- pg_*.h(头文件对应一个系统表的结构定义)的头文件中含
- 定义CATALOG宏,用于统一的模式去定义系统表的结构以及用以描述系统表的数据结构,
- 系统表pg_class的定义通过 CATALOG(pg_ class,1259)
- 宏DATA(x)和 DESCR(x)来定义 Insert,这样Insert可能有多个,用于定义系统表中的初始数据。
- template1是通过运行在bootstrap模式的 postgres程序读取 postgres.bki文件创建的。
- BKI文件是一些用特殊语言写的脚本,
- 这些脚本使 Postgresql后端能够理解,且以特殊的“bocstrap”模式执行,
- 这种模式允许在不存在系统表的零初始条件下执行数据库函数,而普通的SQL命令要求系统表必须存在。
- 因此BKI文件仅用于初始化数据集簇。
2.2.4系统数据库
- 创数据集簇后,集簇默认含三系统数据库
- 1、 0和 postgres
- 1和 0用于创建数椐库。
- 创建数据库命令中用“-T”指定
- 以哪个为模板来创新数据库。
- 1是默认的模板
- 不带“-T”创建的用户数据库是和1一样
- 1是可改的,如果对1改,那么修改之后创建的用户数据库中也能体现出这些修改的结果
- 1的存在许用户可制作一个自定义的模板数据库
- 在其中用户可创建一些应用需要的表、数据、索引等,
- 在日后需要多次创建相同内容的数据库时,都可用1作为模板
- 1内容可被用户改,因此为满足用户创建一个“干净”数据库的需求,
- Pg提供0作为最初始的备份数据
- 需要时可用0作为模板生成“干浄”数据库。
- postgres给初始用户提供一个可连接的数据库,
- 就像 Linux系统中个用户的主目录一样。
- 上述系统数据库都可删除,
- 但在删除前须将其在pg_database中元组的 datistemplate改为FALSE,否则提示“不能删除一个模板数据库”。
2.3 Postgresql进程结构
- Pg主要功能集中Postgres程序
- 人口是Main模块中的min函数
- 初始化数据集簇、启动数据库服务器时,都从这开始
- Main模块确定
- 当前的操作系统平台
- 并据此做一些平台相关的环境变量设置和初始化,
- 然后命令行参数的判断,将控制转到相应的模块
- 图2-4是main的调用流程
- Pg用一种专用服务器进程体系结构,主要是守护进程Postmaster和服务进程 Postgres。
- Postmaster和 Postgres都通过载人 Postgres程序而形成,
- 只是在运行时所处分支不同
- Postmaster负责整个系统启动和关闭。
- 它监听并接受客户端连接请求,为其分配Postgres
- Postgres接受并执行客户端发送的命令。
- 它在底层模块(如存储、事务管理、索引等)之上调用各个主要的功能模块(编译器、优化器、执行器),完成客户端的各种数据库操作,并返执行结果。
2.6服务进程 Postgres
- Postgres进程是接受查询请求并调相应模块处理査询
- 它接受用户命令编译执行,并将结果返给用户。
- 如此循环,直到用户断开
- 命令分两种:查询命令,四种
- 非查询,创建/删表、视图、索引
- 服务进程Postgres根据不同的命令类型选择不同的策略处理。
- 从前面Main主程序的执行流程图(图2-3)中看出, Postgres的启动方式有两种
- 在Postmaster监控下,动态被Postmaster创建为用户服务,
- 多用户的服务方式,也较通常的
- 不经Postmaster以单用户模式直接启动,为单用户提供服务,
- 由-- single启动。
- 这种模式下, Postgres服务器进程须自己完成初始化内存环境、配置参数等,
- 而这些操作在多用户模式下是由 Postmaster服务器进程完成
- Postgres进程位于src/ backend/cop,
- 包括服务进程的postgres.c,
- 是Postgres的人口文件,负责管理查询的整体流程
- 査询命令进行处理query.c,它执行一个分析好的查询
- 非查询命令进行处理utility.c,它执行各种非査询
- dest.c主要处理Postgres和远端客户的一些消息通信操作,
- 并返命令的执行结果。
- Postgres进程的人口是postgres.c中的Postgresmain,
- 工作流程如图2-15。
2.6.1初始化内存环境
- Postgres进程有两种运行方式。
- 多用户模式下被 Postmaster动态创建,则这一部分的工作由 Postmaster完成
- 由于 Postmaster进程和 Postgres进程的特殊关系, Postgres进程中会多次出现这样的情况。
- 全局布尔变量 Isunderpostmaster表明进程的运行状态,
- 为tue表明运行在多用户
- Postgres中内存环境初始化也调Memory Contextlnit完成
2.6.2配置运行参数和处理客户端传递的GUC参数
- 和Postmaster一样,这里配置参数也包三步骤,
- 即将参数设置为默认值、根据命令行参数配置参数、读配置文件重新设置参数。
- 一步和三在多用户模式下(即 Isunderpostmaster为true时)已由 Postmaster完成,而在单用户模式下这三步都和 Postmaster完全相同。
- 命令行方式的参数设置优先级是高于缺省设置的,将会覆盖缺省设置。
- 命令行参数有很多和 Postmaster一样,在 Postgres中仍使用 while+ switch控制结构读入参数并进行配置。
- 之后 Postgres还将从Port结构得到客户端传递的GUC选项,
- 然后根据CUC选项的具体情况调Set Configoption设置。
2.6.3设置信号处理和信号屏破
- Postgres中信号的注册方式和Postmaster类似,
- 这里只对 Postgres中处理的信号及其意义介绍。
- Postgres中信号和对应的信号处理函数如表2-11