第二章 PostgreSQL的体系结构

1. 概述

  PostgreSQL数据库由连接管理系统(系统控制器)、编译执行系统、存储管理系统、事务系统、系统表五大部分组成

  1. 连接管理系统接受外部操作系统对系统的请求,对操作请求进行预处理和分发,起系统逻辑控制作用;
  2. 编译执行系统由查询编译器、查询执行器组成,完成操作请求在数据库中的分析处理和转化工作,最终实现物理存储介质中数据的操作;
  3. 存储管理系统由索引管理器、内存管理器、外存管理器组成,负责存储和管理物理数据,提供对编译查询系统的支持;
  4. 事务系统由事务管理器、日志管理器、并发控制、锁管理器组成,日志管理器和事务管理器完成对操作请求处理的事务一致性支持,锁管理器和并发控制提供对并发访问数据的一致性支持;
  5. 系统表是PostgreSQL数据库的元信息管理中心,包括数据库对象信息和数据库管理控制信息。系统表管理元数据信息,将PostgreSQL数据库的各个模块有机地连接在一起,形成一个高效的数据管理系统。
    在这里插入图片描述

2. 系统表

  在关系数据库中,为了实现数据库系统的控制,必须提供数据字典的功能。数据字典不仅存储各种对象的描述信息,而且存储系统管理所需的各种对象的细节信息。从内容来看,数据字典包含数据库系统中所有对象及其属性的描述信息、对象之间关系的描述信息、对象属性的自然语言含义以及数据字典变化的历史(即数据库的状态信息)。数据字典是关系数据库系统管理控制信息的核心,在pg中系统表扮演着数据字典的角色。
  系统表在PG中表现为存放有系统信息的普通表或视图。用户可以删除然后重建这些表、增加列、插入和更新数值,然而由用户去修改系统表会导致系统信息的不一致性,进而导致系统控制紊乱。正常情况下不应该由用户手工修改系统表,而是由SQL命令关联的系统表操作自动维护系统表信息。比如,创建数据库语句会向pg_database系统表插入一行,并且在磁盘上创建该数据库。
  PostgreSQL的每一个数据库中都有自己的一套系统表,其中大多数系统表都是在数据库创建时从模版数据库拷贝过来的,因此这些系统表里的数据都是与所属数据库相关的。只有少数系统表是所有数据库共享的(比如pg_database)
  由于系统表保存了数据库的所有元数据,所以系统运行时对系统表的访问是非常频繁的。为了提高性能,在内存中建立了共享的系统表CACHE,使用Hash函数和Hash表提高查询效率。
在这里插入图片描述
在PostgreSQL 8.4.1中,共有42张系统表和17张系统视图,系统视图是建立在基本系统表之上的。

2.1 系统表介绍

  • pg_namespace:用于存储命名空间。命名空间层次是: 数据库 · 模式 · 表 · 属性
    当要访问一个对象时,PostgreSQL会按照以下名字空间顺序进行搜索:
  • 特殊名字空间(special),仅用于创建模式;
  • 临时表的名字空间(TEMP);
  • 系统表的名字空间。
    在这里插入图片描述
  • pg_tablespace:存储表空间信息,将表放置在不同的表空间有助于实施磁盘文件布局。pg_tablespace在整个数据集簇里只有一份,而不是每个数据库都有自己的pg_tablespace表。
       PostgreSQL表空间允许在文件系统里定义代表数据库对象的文件的存放位置。通过使用表空间,可以控制一个PostgreSQL中数据的磁盘布局,即可以通过表空间将 PostgreSQL 系统的数据分布在不同的磁盘位置上。这样做有两个用处。第 一,如果初始的集筷所在 的分区或者卷用光了空间,而又无法扩展该分区或卷的空间,那么可以通过表空间去利用另 一个分 区的空间;第二,表空间允许管理员根据数据库对象的使用模式安排数据位置,从而优化性能
    在这里插入图片描述
  • pg_database:存放了当前数据集簇中数据库的信息,它也是一个在整个集簇范围内共享的系统表。
    在这里插入图片描述
  • pg_class: 存储表及与表类似结构的数据库对象信息,包括索引、序列、视图、复合数据类型、TOAST表等。在这里插入图片描述
    在这里插入图片描述
  • pg_attribute:存储表的属性信息,对于数据库中表的每个属性都有一个元组。
    在这里插入图片描述
    关键系统表之间的关系
    在这里插入图片描述

2.2 系统视图

在这里插入图片描述
   系统表PostgreSQL数据库系统运行控制信息的来源,是数据库系统的核心组成部分。虽然用 户可以操作,但为维护系统表信息的 一致性,系统表将由系统统 一维护。在PostgresQL 数据库安装完后,需要先进行初始化数据库操作 ( initdb),生成模板数据库和相应的目录、文件信息,系统表 即在此阶段生成。而用户数据库及其系统表都是从模板数据库进行复制生成的。

3. 数据集簇

   PostgresQL.安装完成后,在做任何其他事情之前,必须先使用initdb 程序初始化磁盘上的数据存储区,即数据集族,由PostgreSQL管理的用户数据库以及系统数据库总称为数据集族。在PostgresQL的实现中,数据库就是磁盘上一些文件的集合,只不过这些文件有特定的文件名、存储位置等,并且有些文件之间会相互关联。
   对象标识符号(OID)用来在整个数据集簇中唯一地标识一个数据库对象,可以是数据库、表、索引、视图、元组、类型等。它是一个无符号整数。
    在系统运行时可分配等OID资源实际是从16384开始的,因为需要预留一部分OID资源给系统表等数据库对象。
    初始化数据集簇包括创建数据库系统所有数据的数据目录、创建共享的系统表、创建其他的配置文件和控制文件,并创建三个数据库:模版数据库template1和template0、默认的用户数据库postgres。以后用户创建一个新数据库时,template1数据库里的所有内容(包括系统表文件)都会拷贝过来。因此,任何在template1里面安装的内容都自动拷贝到之后创建的数据库中。template0和postgres都是通过拷贝template1创建的。
    对于具体的数据库,在PGDATA/base里都对应有一个子目录,子目录的名字是该数据库在系统表pg_database里的OID。
    每个表和索引都存储在其所属数据库目录下的独立文件里,以该表或该索引的filenode号命名,该号码记录在pg_class中的relfilenode属性中。
    在表或者素引超过1GB之后,它就被分裂成多个1GB大小的段。第 一个段的文件名和filenode 相同,随后的段命名为filenode1,filenode2······这样的策略避免了在某些有文件大小限制的平台 上可能出现的问题。
    如果一个表的有些属性要存储相当大的数据,就会有个与之关联的TOAST表,用于存储无法在数据行中放置的超大外置数据。
在这里插入图片描述

3.1 initdb的使用

    initdb是在使用PostgreSQL之前用于初始化数据库集簇的程序,它负责创建数据库目录、系统表、模版数据库
在这里插入图片描述

3.2 postgres.bki

    后端接口postgres.bki文件是在编译过程中由/src/backend/catalog目录下的脚本程序genbki.sh读取/src/include/catalog目录下的以.h结尾的系统表定义文件创建,并通常放在安装树的share子目录下。在pg_*.h的头文件中包含如下内容的定义:

  1. 定义Catalog宏,用于以统一的模式去定义系统表的结构及用以描述系统表的数据结构;
  2. 通过宏DATA(x)和DESCR(x)来定义insert操作,用于定义系统表中的初始数据。
        模版数据库template1是通过运行在bootstrap模式的postgres程序读取postgres.bki文件创建的。
        notes: bootstrap模式允许在不存在系统表的零初始化条件下执行数据库函数,而普通的SQL命令要求系统表必须存在。因此BKI文件仅用于初始化数据集簇
        BKI命令格式如下:
  3. create [bootstrap] [shared_relation] [without_Oids] tablename tablename tableOid (name1 = type1 [, name2 = type2, ...])
    在这里插入图片描述
  4. open tablename
        打开一个名为tablename的表,准备插入数据。在BKI被执行的时候,每一个时刻都只有一个表被打开。
  5. insert [ OID = Oid_value] (value1 value2 ... )
  6. close [tablename]
  7. declare [unique] index indexname indexOid on tablename using amname (opclass1 name1 [, ...])
  8. declare toast toasttableOid toastindexOid on tablename
  9. build indices
        对使用5、6两种命令创建的索引进行内容填充。在这里插入图片描述

3.3 initdb的执行过程

    执行initdb程序时,将从initdb.c文件中的main函数开始执行。initdb执行时将按照顺序执行下列工作:

  1. 根据用户输入的命令行参数获取输入的命令名;
  2. 设置系统编码LC_ALL,查找执行命令的绝对路径并设置该路径;
  3. 设置环境变量(pg_data等),获取系统配置文件的源文件路径(postgres.bki、postgresql.conf、sample等文件),并检查该路径下各文件的可用性;
  4. 设置中断信号处理函数,对中断命令行SIGHUP、程序中断SIGINT、程序退出SIGQUIT、软件中断SIGTREM和管道中断SIGPIPE等信号进行屏蔽,保证初始化工作顺利进行;
  5. 创建数据目录,以及该目录下一些必要的子目录,如base、global、base/1等;
  6. 测试当前服务器系统性能,由测试结果创建配置文件postgresql.conf、pg_hba.conf、pg_ident.conf,并对其中定义的参数做一些设置;
  7. 在bootstrap模式下创建数据库template1,存储在数据目录等字目录base/1中;
  8. 创建系统视图、系统表TOAST表等,复制template1来创建template0和postgres,这些操作用普通的SQL命令来完成;
  9. 打印操作成功等相关信息,退出。
        总结: initdb是PostgreSQL中一个独立的程序,它的主要工作是对数据集簇进行初始化,创建模板数据库和系统表,并向系统表中插入初始元组。在这以后,用户创建各种数据库、表、视图、索引等数据库对象和进行其他操作时,都是在模板数据库和系统表的基础上进行的。
    在这里插入图片描述

3.4 系统数据库

    在创建数据库集簇之后,该集簇中默认包含三个系统数据库template1、template0和postgres。其中template0和postgres都是在初始化过程中从template1拷贝而来的。
    template1和template0数据库用于创建数据库。PostereSQL中采用从模板数据库复制的方式来创 建新的数据库,在创建数据库的命令中可以用 “- T〞选项来指定以哪个数据库为模板来创建新数据库。
    template1数据库是创建数据库命令默认的模板。template1是可以修改的,如果对template1进行了修改,那么在修改之后创建的用户数据库中也能体现出这些修改的结果。
    由于template1的内容有可能被用户修改,因此提供了template0数据库作为最初始的备份数据,当需要时可用template0作为模板生成“干净”的数据库。
    第三个初始数据库postgres用于给初始用户提供一个可连接的数据库。
    上述系统数据库都是可以删除的,但是两个模板数据库在删除之前必须将其在pg_database中元组的datistemplate属性改为FALSE,否则删除会提示 “不能刪除一个模板数据库”。

4. PostgreSQL进程结构

    Postgres程序的入口是Main模块的main函数,在初始化数据库集簇、启动数据库服务器时,都将从这里开始执行。Main模块主要的工作是确定当前的操作系统平台,并据此做一些平台相关的环境变量设置和初始化,然后通过对命令行参数的判断,将控制转到相应的模块中去。
PostgreSQL系统主函数main流程
    PostgreSQL使用一种专用服务器进程体系结构,其中,最主要的两个进程就是守护进程Postmaster和服务进程Postgres。从本质上来说,Postmaster和Postgres都是通过载入Postgres程序而形成的进程,只是在运行时所处的分支不同而已。

  • 守护进程Postmaster负责整个系统的启动和关闭。它监听并接受客户端的连接请求,为其分配服务进程Postgres。该进程除为用户连接请求分配后台Postgres服务进程外,还将启动相关的后台辅助进程。守护进程在完成基本运行环境初始化、创建接受用户请求的监听端口后,顺序启动如下 系统辅助进程:SysLogger(系统日志进程)、PgStat(统计数据收集进程)、AutoVacuum(系统自动清理进程)。 在守护进程Postmaster进入到循环监听中时启动如下进程:BgWriter(后台写进程)、Wal Writer(预写式日志写进程)、PgArch(预写式日志归档进程)。
  • 服务进程Postgres接受并执行客户端发送的命令。它在底层模块(如存储、事务管理、索引等)之上调用各个主要功能模块(如编译器、优化器、执行器等),完成客户端的各种数据库操作,并返回执行结果。
    在这里插入图片描述
        PostgreSQL采用C/S模式,系统为每个客户端分配一个服务进程。即Postmaster总是监听用户连接请求并为用户分配服务进程Postgres,而Postgres则负责为客户端执行各种命令。

5. 守护进程Postmaster

    完成数据库集簇初始化后,用户可以启动一个数据库实例来运行数据库管理系统,多用户模式下一个数据库实例由数据库服务器守护进程Postmaster来管理。它是一个运行在服务器上的总控进程,负责整个系统的启动和关闭,并且在服务进程出现错误时完成系统的修复。它管理数据库文件、监听并接受来自客户端的连接请求,并且为客户端连接请求fork一个Postgres服务进程,来代表客户端在数据库上执行各种命令。同时,Postmaster还管理与数据库运行相关的辅助进程。
    用户还可以使用postmaster、postgres或pg_ctl命令启动Postmaster。
    Postmaster就像一个处理客户端请求的调度中心。当客户端程序需要对数据库进行操作时,首先会发出一个初始消息给Postmaster进行请求。Postmaster将根据这个初始消息中的信息对客户端的身份进行验证,如果身份验证通过,Postmaster就为该客户端新建一个服务进程Postgres。随后Postmaster将与客户端的交互工作转交给Postgres服务进程,由Postgres来完成客户端所需的数据库操作。
在这里插入图片描述
    Postmaster也负责管理整个系统范围的操作,例如中断等操作,Postmaster本身不进行这些操作,它只是指派一个子进程在适当的时间去处理它们。同时,它要在数据库崩溃的时候重启系统。Postmaster进程在起始时会建立共享内存和信号库,Postmaster及其子进程的通信就通过共享内存和信号来实现。这种多进程设计使得整个系统的稳定性更好,即使某个后台进程崩溃也不会影响系统中其他进程的工作,Postmaster只需要重置共享内存即可从单个后台进程的崩溃中恢复。
在这里插入图片描述

5.1 初始化内存上下文

    程序首先调用MemoryContextInit创建TopMemoryContext和ErrorContext,然后调用AllocSetContextCreate以TopMemoryContext为根节点创建PostmasterContext,最后将全局指针Current MemoryContext指向PostmasterContext。这些内存上下文的具体含义如下:

  • TopMemoryContext:在TopMemoryContext中分配的内存直到系统退出时才会释放。例如它存放了所有打开的文件描述符、内存上下文的控制节点等。它是所有内存上下文的树根;
  • ErrorContext:这是错误恢复处理的永久性内存环境,恢复完毕则重设;
  • PostmasterContext:这是Postmaster正常工作的内存环境,由它通过fork函数产生的子进程将会删除这个环境。

5.2 配置参数

    在初始化内存环境之后,需要配置Postmaster运行时所需的各种参数。GUC(Grand Unified Configuration)模块实现了多种数据类型(目前有boolean、int、float、string四种)的变量配置。
在这里插入图片描述
    每一种数据类型的GUC参数都由两部分组成:共性部分和特性部分
    共性部分的参数数据类型config_type有五种:PGC_BOOL(布尔型)、PGC_INT(整型)、PGC_RE-AL(实数)、PGC_STRING(字符串)和PGC_ENUM(枚举)。特性部分的第一项都是一个指向其共性数据结构的指针。
    Postmaster配置参数的基本过程包括:

  • 初始化GUC参数:将参数设置为默认值;
  • 配置GUC参数:根据命令行参数配置参数;
  • 读取配置文件:读配置文件重新设置参数。在这里插入图片描述
        当确定了只有自己在运行时,还将调用RemovePgTempFiles函数删除PGDATA/base/pgsql_tmp中的临时文件pgsql_tmp*以及非默认表空间中的临时文件。

5.3 创建监听套接字

    PostgreSQL允许通过网络或UNIX本地机来访问数据库。

  • 字符串ListenAddresses:该字符串中存储的是服务器的IP地址,如果是多接口主机的话,IP地址之间用“ , ”隔开,“ * ”表示所有可用IP接口,缺省值为“localhost”;
  • 整型数组ListenSocket[MAXLISTEN]:该数组用来保存与服务器上某个IP地址绑定的监听套接字描述符,初始时全为-1,MAXLISTEN的值为64;
  • struct addrinfo结构体:该结构体用来保存我们调用哦getaddrinfo系统函数返回与协议无关的套接字时需要关心的信息,如要监听的服务器IP地址、服务器端口等相关信息。
        BackendList是一个活动的后台进程表,主要用于跟踪和了解目前有多少子进程,并且在必要的时候给它们发送适当的信号。该进程表主演记录的是由Postmaster通过fork产生的Postgres进程,特殊的子进程如Startup和BgWriter不在这个表中。

5.4 注册信号处理函数

    信号是操作系统响应某些错误状况而产生的事件,它可以明确地由一个进程发给另一个进程,用这种办法传递信息或协调操作行为。
    进程有权选择响应或屏蔽信号(SIGKILL和SIGSTOP不能屏蔽)。Postmaster定义了三个信号集:BlockSig是要屏蔽的信号集;UnBlockSig是不希望屏蔽的信号集;AuthBlockSig是在进行用户连接认证时需要屏蔽的信号集,它们都是位向量。

  1. 信号处理函数SIGHUP_handler
        当配置文件发生改变时产生SIGHUP信号。Postmaster进程在收到SIGHUP信号时重读配置文件postgresql.conf,然后向子进程发同样的信号,并重新装载pg_hba.conf和pg_ident.conf文件
  2. 信号处理函数pmdie
        pmdie处理三种信号:SIGTERM、SIGINT和SIGQUIT。在这里插入图片描述
    在这里插入图片描述
  3. 信号处理函数reaper
        当系统中有子进程退出的时候,子进程就会给Postmaster发送一个SIGCHLD信号。Postmaster收到SIGCHLD信号后调用reaper函数清理退出的子进程。

5.5 辅助进程启动

    在Postmaster的创建过程中会首先启动SysLogger日志进程,并完成PgStat进程、AutoVacuum进程的初始化工作,而在Postmaster的监听循环中检测辅助进程的状态,并新建或重新创建这些辅助进程。

  1. SysLogger辅助进程
    在这里插入图片描述
  2. 辅助进程初始化
        SysLogger辅助进程启动完成后,Postmaster开始对辅助进程PgStat进程、AutoVacuum进程进行初始化操作,为进程分配必要的资源。
        辅助进程的初始化完成后,Postmaster启动一个辅助过程(函数StartupProcess)进行数据库的启动操作。其他辅助进程的启动将在循环等待连接ServerLoop中检查和启动。

5.6 装载客户端认证文件

    注册完信号处理函数后,将逐行读取data目录下的pg_hba.conf和pg_ident.conf两个配置文件的内容到链表变量中,以用于控制客户端认证。
在这里插入图片描述

5.7 循环等待客户连接请求

    Postmaster会调用ServerLoop函数来循环等待客户端的连接请求,该函数主体是一个死循环,它的主要功能就是在监听到用户的连接请求后建立与该用户的连接,然后通过调用fork函数复制出一个Postgres进程为该用户服务。
    Postmaster始终都是只执行管理工作,通过派生出各种辅助进程来执行相关功能。
在这里插入图片描述
在这里插入图片描述

6. 辅助进程

    在Postmaster进程中,为每个辅助进程设置了一个全局变量来标识该进程的进程号,分别为SysLoggerPID、BgWriterPID、WalWriterPID、AutoVacPID、PgArchPID、PgStatPID。当这些变量值为0时,表示相应的进程尚未启动。只有系统日志辅助进程Syslogger在Postmaster进入监听循环之前完成启动操作,在监听循环中检测其状态进行重启操作;其他辅助进程的进程号在进入监听循环之前都被设置为0,因此它们的初次启动和重新启动操作都会在Postmaster的监听循环中执行。在监听循环ServerLoop中,每一次循环时都会检查各个辅助进程号所对应的全局变量值是否为0,并根据系统中进程运行状态机标志变量pmState的状态值来启动相应的辅助进程。

6.1 SysLogger系统日志进程

   在SysLogger的配置选项中可以设置日志文件的大小,SysLogger会在日志达到指定大小时关闭当前日志文件,产生新的日志文件。
在这里插入图片描述
    系统日志辅助进程的入口位置为SysLogger_Start函数。在这里插入图片描述

6.2 BgWriter后台写进程

    BgWriter是PostgreSQL中在后台将脏页写出到磁盘的辅助进程,引入该进程主要为达到如下两个目的:首先,数据库在进行查询处理时若发现要读取的数据不在缓冲区中时要先从磁盘中读入要读取的数据所在的页面,此时如果缓冲区已满,则需要先选择部分缓冲区中的页面替换出去。如果被替换的页面没有被修改过,那么可以直接丢弃;但如果要被替换的页已被修改,则必须先将这页写出到磁盘中才能替换,这样数据库的查询处理就会被阻塞。通过使用BgWriter定期写出缓冲区的部分脏页到磁盘中,为缓冲区腾出空间,就可以降低查询处理被阻塞的可能性。其次,PostgreSQL在定期作检查点时需要把所有脏页写出到磁盘,通过BgWriter预先写出一些脏页,可以减少设置检查点(CheckPoint)时要进行的IO操作,使系统的IO负载趋向平稳。通过BgWriter对共享缓冲区写操作的统一管理,避免了其他服务进程在需要读入新的页面到共享缓冲区时,不得不将之前修改过的页面写出到磁盘的操作。不过,当BgWriter无法维护足够的干净共享缓冲区时,其他服务进程仍可以自行完成将脏页写回磁盘的操作。BgWriter同时也辅助处理所有的检查点,它也会定期地发出一个检查点请求,当然也可以由其他进程通过信号要求BgWriter执行一个检查点。
    在BgWriter参数的配置中,如果BgWriter过于频繁地将脏页写出,则经常被更新的数据页很可能会被一次又一次地写出到磁盘上,反而增加了数据库的IO次数,进而导致系统性能下降;另一方面,若BgWriter写周期过长,又不能起到优化数据库写IO操作的作用。在这里插入图片描述
在这里插入图片描述

6.3 WalWriter预写式日志写进程

    预写式日志WAL(Write Ahead Log,也称Xlog)的中心思想是对数据文件的修改必须是只能发生在这些修改已经记录到日志之后,也就是先写日志后写数据。使用WAL主要的好处就是显著地减少了写磁盘的次数,因为在日志提交的时候只需要把日志文件刷新到磁盘,而不是事务修改的所有数据文件。在多用户环境里,许多事务的提交可以用日志文件的一次fsync来完成,而且日志文件是顺序写的,因此同步日志的开销远比同步数据块的开销小。同BgWriter一样,其他服务进程在WalWriter出错时也允许直接进行预写日志写操作。
    WAL日志文件存放在数据集簇中的pg_xlog目录里。它是作为一个段文件的集合存储的,每个段16MB,并分割成若干页,每页8KB。日志记录头格式在xlog.h里描述。日志内容取决于它记录的事件的类型,一个段文件的名字由24个十六进制字符组成,分为三个部分,每个部分由8个十六进制字符组成。第一部分表示时间线,第二部分表示日志文件标号,第三部分表示日志文件的段标号。时间线由1开始,日志文件标号和日志文件的段标号由0开始。所以系统中第一个事务日志文件是000000010000000000000000,第二个事务日志文件是000000010000000000000001。这些数字不能循环使用。
    WAL的缓冲区和控制结构在共享内存里,它们都是用轻量的锁保护的,对共享内存的需求由缓冲区数量决定,默认的WAL缓冲区大小时8个8KB的缓冲区。出于安全考虑,可以将日志文件和数据文件分别存储在不同的磁盘上,可以通过把pg_xlog目录移动到另外一个位置,然后在数据集簇里原来的位置创建一个指向新位置的符号链接来实现。
在这里插入图片描述
    WalWriter的处理流程和BgWriter非常相似。只是WalWriter定期写磁盘的是存放预写式日志的WAL缓冲区,而BgWriter定期写入磁盘的是存放普通数据的共享缓冲区。

6.4 PgArch预写式日志归档进程

    PITR(Point-In-Time-Recovery)技术支持将数据库恢复到其运行历史中任意一个有记录的时间点。PITR的另一个重要的基础就是对WAL文件的归档功能。PgArch辅助进程的目标就是对WAL日志在磁盘上的存储形式进行归档备份。
在这里插入图片描述
在这里插入图片描述

6.5 AutoVacuum系统自动清理进程

    在pg数据库中,对表元组的UPDATE或DELETE操作并未立即删除旧版本的数据,表中的旧元组只是被标识为删除状态,并未立即释放空间。这种处理对于获取多版本并发控制是必要的。当事务提交后,过期元组将对事务不再有效,因而其占据的空间必须回收以供其他新元组使用,以避免对磁盘空间增长的无休止的需求,此时对数据库的清理工作通过运行VACUUM来实现。
    AutoVacuum(系统自动清理进程)自动执行VACUUM和ANALYZE命令,回收被标识为删除状态记录的空间,更新表的统计信息。
在这里插入图片描述
    AutoVacuum系统自动清理进程中包含两种不同的处理进程:AutoVacuum Launcher和AutoVacuum Worker

  • AutoVacuum Launcher进程为监控进程,用于收集数据库运行信息,根据数据库选择规则选中一个数据库,并调度一个AutoVacuum Worker进程执行清理操作;
  • AutoVacuum Worker进程执行实际的清理任务,Launcher进程中维护有Worker进程列表。
        AutoVacuum Launcher进程选择数据库的规则如下:首先由于数据库事务XID是32位整数且递增分配,当超过最大值时会从头开始计数使用,而事务XID的大小标识事务开始的时间,事务XID重新计数使用会使数据库中部分事务数据丢失,因而当XID超过配置的autovacuum_freeze_max_age时,强制对该数据库进行清理并更新事务XID;其次,若无强制清理操作,则选择数据库列表中最早未执行过自动清理操作的数据库。
        AutoVacuum Worker进程列表由三种不同状态的进程列表构成,即空闲的Worker进程列表、正在启动的Worker进程、运行中的Worker进程列表。Launcher进程在不同状态之间的切换实现了Worker进程的调度工作。首先,在初始化阶段创建的运行内存上下文中,创建长度为autovacuum_max_workers的空闲Worker进程描述信息列表,而正在启动Worker进程和运行中的Worker进程的列表被置为空。如果Launcher进程需要一个Worker进程,空闲Worker进程列表不为空且当前没有正在启动中的Worker进程,则开始一个启动Worker进程的操作,即向Postmaster进程发送启动消息,从空闲Worker进程列表中取出一个进程描述信息,设置为启动中状态。Launcher进程中只允许存在一个启动中状态的Worker进程,启动中的Worker进程如果超时将被取消并重新开始启动Worker进程的循环。如果Worker进程启动成功,将启动成功的Worker进程信息添加到运行中的Worker进程列表中。运行中的Worker进程即连接上根据规则选中的数据库。在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

6.6 PgStat统计数据收集进程

    PgStat辅助进程是统计信息收集器,它专门负责收集数据库系统运行中的统计信息,如在一个表和索引上进行了多少次插入与更新操作、磁盘块的数量和元组的数量、每个表上最近一次执行清理和分析操作的时间,以及统计每个用户自定义函数调用执行的时间等。由于统计数据收集给查询处理增加了一些负荷,因此,是否收集信息是可配置的。系统表pg_statistic中存储了PgStat收集的各类统计信息,另外在数据库集簇的目录下有与统计信息收集器相关的文件:global子文件夹下的pgstat.stat文件用于保存当前全局的统计信息;pg_stat_tmp文件则是PgStat进程和各个后台进程进行交互的临时文件所在地
    PgStat辅助进程收集的统计信息主要用于查询优化时的代价估算。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7. 服务进程Postgres

    Postgres进程是实际的接受查询请求并调用相应模块处理查询的Postgres服务进程。它直接接受用户的命令进行编译执行,并将结果返回给用户。如此循环,直到用户断开连接。用户的命令分为两种:一种是查询命令,即插入、删除、更新和选择四种命令;另一种是非查询命令,如创建/删除表、视图、索引等命令。
    Postgres的启动方式有两种:一种是在Postmaster监控下,动态地被Postmaster创建为用户服务,这是一种多用户的服务方式,也是比较通常的启动方式;另外一种是不经过Postmaster以单用户模式直接启动,为单一用户提供服务,这种方式由-- single选项启动。在这种模式下,Postgres服务器进程必须自己完成初始化内存环境、配置参数等操作,而这些操作在多用户模式下是由Postmaster服务器进程完成的。
    Postgres进程的主要源代码文件位于src/backend/tcop文件夹下,主要文件包括:

  • 服务进程的源代码文件postgres.c,它是Postgres的入口文件,负责管理查询的整体流程;
  • 对于查询命令进行处理的源代码文件pquery.c,它执行一个分析好的查询命令;
  • 对于非查询命令进行处理的源代码文件utililty.c,它执行各种非查询命令;
  • dest.c中的代码主要处理Postgres和远端客户的一些消息通信操作,并负责返回命令的执行结果。在这里插入图片描述

7.1 初始化内存环境

7.2 配置运行参数和处理客户端传递的GUC参数

    配置参数包括:将参数设置为默认值、根据命令行参数配置参数、读配置文件重新设置参数。

7.3 设置信号处理和信号屏蔽

在这里插入图片描述

7.4 初始化Postgres的运行环境

在这里插入图片描述
在这里插入图片描述

7.5 创建内存上下文并设置查询取消跳跃点

    创建一个名为MessageContext的内存上下文,该内存上下文用于存储从前端发送过来的消息中的查询命令,以及在查询过程中产生的中间数据,每当PostgresMain进行下一次循环时该内存上下文将被重设,即所有经过MessageContext分配的内存块将被释放。
    创建完成后将调用sigsetjmp(系统调用函数)设置跳跃点,当客户端取消一次查询请求或发生错误时,将通过调用siglongjmp利用全局变量PG_exception_stack(该变量是指向跳跃点的指针)从这个点退出当前事务然后重新开始查询,在错误恢复期间不允许被中断,也不接受任何客户端取消查询的请求(正在取消)。

7.6 循环等待处理查询

    服务进程与用户进程通信过程中所涉及的数据结构:

  • 共享缓冲区PqSendBuffer:用来接收服务器发送给客户端的消息;
  • 共享缓冲区PgRecvBuffer:用来接收客户端发给服务器的消息;
        客户端有两种方式递交请求:一种是通过网络连接,调用SocketBackend函数;另一种是客户端和服务器在同一台机器上,调用InteractiveBackend函数从交互终端读取客户端请求。

7.7 简单查询的执行流程

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值