体系结构
数据库:PostgreSQL 数据库是由一系列位于文件系统上的物理文件组成,通常将这些物理文件称为数据库,
将这些物理文件、管理这些物理文件的进程、进程管理的内存称为这个数据库的实例。
PostgreSQL 的内部功能实现上,可以分为:
系统控制器:负责接收外部连接请求
查询分析器:对连接请求查询进行分析并生成优化后的查询解析树,从文件系统获取结果集或通过事务系统对数据做处理,并由文件系统持久化数据
事务系统
恢复系统、
文件系统
.....
逻辑存储结构
数据库集簇( Database Cluster ):指由单个PostgreSQL 服务器实例管理的数据库集合,组成数据库集簇的这些数据库使用相同的全局配置文件和监昕端口、共用进程和内存结构
数据库集群:一组数据库服务器构成的集群
Database Cluster:
数据库Database(Database1...Databasen)
Schema
表、索引、序列、视图、函数等这些对象
Users
创建一个Database 时会为这个Database创建一个名为public 的默认Schema ,每个Database 可以有多个Schema
在这个数据库中创建其他数据库对象时如果没有指定Schema ,默认创建在public这个Schema 中。
Schema 可以理解为一个数据库中的命名空间,在数据库中创建的所有对象都在Schema中,不同的Schema 中可以有多个相同名称的Table 、Index 、View 、Sequence、Function 等数据库对象。
一个用户可以从同一个客户端连接中访问不同的Schema 。
物理存储结构
数据库的文件默认保存在initdb 时创建的数据目录中。包括:
数据文件
参数文件
控制文件
数据库运行日志
预写日志
......
数据目录结构:
~]# yum install tree
查看数据目录下文件
~]# tree -L 1 -d /opt/pg/data/9.5/
/opt/pg/data/9.5/
├── base
├── global
├── pg_clog
├── pg_commit_ts
├── pg_dynshmem
├── pg_log
├── pg_logical
├── pg_multixact
├── pg_notify
├── pg_replslot
├── pg_serial
├── pg_snapshots
├── pg_stat
├── pg_stat_tmp
├── pg_subtrans
├── pg_tblspc
├── pg_twophase
└── pg_xlog
目录 用途
base 包含每个数据库对应的子目录的子目录
global 包含集簇范围的表的子目录,比如pg_database
pg_commit_ts 包含事务提交时间戳数据的子目录
pg_xact 包含事务提交状态数据的子目录
pg_dynshmem 包含被动态共享内存子系统所使用文件的子目录
pg_logical 包含用于逻辑复制的状态数据的子目录
pg_mult1xact 包含多事务状态数据的子目录(用于共享的行锁)
pg_notify 包含LISTEN/NOTIFY 状态数据的子目录
pg_replslot 包含复制槽数据的子目录
pg_serial 包含已提交的可序列化事务信息的子目录
pg_snapshots 包含导出的快照的子目录
pg_stat 包含用于统计子系统的永久文件的子目录
pg_stat_tmp 包含用于统计信息子系统临时文件的子目录
pg_subtrans 包含子事务状态数据的子目录
pg_tblspc 包含指向表空间的符号链接的子目录
pg_twophase 用于预备事务状态文件的子目录
pg_wal 保存预写日志
pg_xact 记录事务提交状态数据
文件 用途
PG_VERSION PostgreSQL 主版本号文件
pg_hba.conf 客户端认证控制文件
postgresql.conf 参数文件
postgresql.auto.conf 参数文件,只保存ALTER SYSTEM 命令修改的参数
postmaster.opts 记录服务器最后一次启动时使用的命令行参数
数据文件布局
数据目录中的base 子目录是我们的数据文件默认保存的位置,是数据库初始化后的默认表空间。
对象标识符( OID ):
PostgreSQL 中的所有数据库对象都由各自的对象标识符( OID )进行内部管理,它们是无符号的4 字节整数。
pg=# SELECT oid, datname FROM pg_database WHERE datname='cdm';
oid | datname
-------+---------
24577 | cdm
(1 row)
数据库中的表、索引、序列等对象的OID 存储在pg_class 系统表中,可以查询获得这些对象的OID:
pg=# \c cdm
You are now connected to database "cdm" as user "pg".
cdm=# SELECT oid, relname,relkind FROM pg_class WHERE relname='network_identity_thing';
oid | relname | relkind
--------+------------------------+---------
143110 | network_identity_thing | r
(1 row)
表空间
数据库中创建的对象都保存在表空间中,例如表、索引和整个数据库都可以被分配到特定的表空间。
在创建数据库对象时,可以指定数据库对象的表空间,如果不指定则使用默认表空间,也就是数据库对象的文件的位置。
cdm=# \db
List of tablespaces
Name | Owner | Location
------------+-------+----------
pg_default | pg |
pg_global | pg |
(2 rows)
pg_global 表空间的物理文件位置在数据目录的 global目录中,它用来保存系统表。
pg_default 表空间的物理文件位置在数据目录中的 base目录,是templateO 和 templatel 数据库的默认表空间,我们知道创建数据库时,默认从template1 数据库进行克隆,因此除非特别指定了新建数据库的表空间,默认使用templatel 的表空间pg_default 。
用户还可以创建自定义表空间
1. 使用操作系统的postgres 用户创建一个目录
-bash-4.2$ mkdir -p /opt/pg/data/9.5/steventblspc
2. 连接到数据库
~]$ psql -h pg01 -p 1523 -U pg
3. 使用CREATE TABLESPACE 命令创建表空间
pg=# CREATE TABLESPACE stevespc LOCATION '/opt/pg/data/9.5/steventblspc';
4. 创建数据库对象的时候指明使用的表空间
pg=# CREATE TABLE steven_test(id serial,name varchar) TABLESPACE stevespc;
我们在数据库pg下创建的,因此
pg=# SELECT oid, datname FROM pg_database WHERE datname ='pg' ;
oid | datname
-------+---------
16384 | pg
(1 row)
pg的表、索引都会保存在$PGDATA/base/16384 这个目录中/opt/pg/data/9.5/base/16384
我们制定新建表的表空间stevespc,其数据位置 /opt/pg/data/9.5/steventblspc/PG_9.5_201510051/16384
数据文件的命名:
在数据库中创建对象,例如表、索引时首先会为表和索引分配段。在PostgreSQL 中,每个表和索引都用一个文件存储,新创建的表文件以表的OID 命名, 对于大小超出l GB 的表数据文件, PostgreSQL 会自动将其切分为多个文件来存储【超出lGB 之外的数据会按每GB 切割,】,切分出的文件用OID.<顺序号>来命名。
但表文件并不是总是OID.<顺序号>命名,实际上真正管理表文件的是pg_class 表中的relfilenode 字段的值,在新创建对象时会在pg_class 系统表中插入该表的记录,默认会以OID 作为relfilenode 的值,但经过几次VACUUM 、TRUNCATE 操作之后,relfilenode 的值会发生变化。有可能命名规则为<relfilenode>.<顺序号> 。
SELECT oid,relfilenode FROM pg_class WHERE relname ='steven_test';
pg=# SELECT oid,relfilenode FROM pg_class WHERE relname='steven_test';
oid | relfilenode
--------+-------------
532824 | 532824
(1 row)
~]# ll /opt/pg/data/9.5/steventblspc/PG_9.5_201510051/16384
total 8
-rw-------. 1 pg dba 0 Jul 16 04:31 532824
-rw-------. 1 pg dba 0 Jul 16 04:31 532828
-rw-------. 1 pg dba 8192 Jul 16 04:31 532830
表文件内部结构
在PostgreSQL 中:
将保存在磁盘中的块称为Page
将内存中的块称为Buffer
表和索引称为Relation
行称为Tuple
每个 Tuple 包含两部分的内容:
一部分为HeapTupleHeader ,用来保存Tuple 的元信息,包含该Tuple 的OID 、xmin 、cmin 等;
另一部分为HeapTuple ,用来保存Tuple 的数据。
数据的读写是以Page 为最小单位, 每个Page 默认大小为8kB ,在编译PostgreSQL 时指定的。BLCKSZ 大小决定Page 的大小。
每个表文件由多个BLCKSZ 字节大小的Page 组成, 每个Page 包含若干Tuple 。
进程结构:
PostgreSQL 是一用户一进程的客户端/服务器的应用程序。
数据库启动时会启动若干个进程,其中有
postmaster (守护进程)、
postgres (服务进程)、
sys_logger 、
check_point
bgwriter
walwriter 等辅助进程。
守护进程与服务进程
postmaster 进程的主要职责有:
口数据库的启停。
口监听客户端连接。
口为每个客户端连接fork 单独的postgres 服务进程。
口当服务进程出错时进行修复。
口管理数据文件。
口管理与数据库运行相关的辅助进程。
当客户端调用接口库向数据库发起连接请求,守护进程postmaster 会fork 单独的服务进程postgres 为客户端提供服务,此后将由postgres 进程为客户端执行各种命令,客户端也不再需要postmaster 中转,直接与服务进程postgres 通信,直至客户端断开连接,
辅助进程
口background writer :也可以称为bgwriter 进程, bgwriter 进程很多时候都是在休眠状态,每次唤醒后它会搜索共享缓冲池找到被修改的页,并将它们从共享缓冲池刷出。
口autovacuum launcher : 自动清理回收垃圾进程。
口WALwriter :定期将WAL 缓冲区上的WAL 数据写入磁盘。
口statistics collector :统计信息收集进程。
口logging collector :日志进程,将消息或错误信息写入日志。
口archiver : WAL 归档进程。
口checkpointer :检查点进程。
内存结构
PostgreSQL 的内存分为两大类:
本地内存
共享内存
另外还有一些为辅助进程分配的内存等
本地内存
本地内存由每个后端服务进程分配以供自己使用,当后端服务进程被fork 时,每个后端进程为查询分配一个本地内存区域。
本地内存由三部分组成: work_mem 、maintenance_work_mem 和temp_buffers。
work_mem :当使用ORDER BY 或DISTINCT 操作对元组进行排序时会使用这部分内存。
maintenance_work mem : 维护操作,例如VACUUM 、REINDEX 、CREATE INDEX等操作使用这部分内存。
temp_buffers :临时表相关操作使用这部分内存。
共享内存
共享内存在PostgreSQL 服务器启动时分配,由所有后端进程共同使用。共享内存主要由三部分组成:
shared buffer pool : PostgreSQL 将表和索引中的页面从持久存储装载到这里, 并直接操作它们。
WAL buffer: WAL 文件持久化之前的缓冲区。
CommitLog buffer : PostgreSQL 在Commit_Log 中保存事务的状态,并将这些状态保留在共享内存缓冲区中,在整个事务处理过程中使用。