走进 PostgreSQL 世界第一篇章--内部结构
在日常的应用程序开发过程中,都离不开数据库的使用。今天就带大家走进非常有名的关系型数据库管理系统:PostgreSQL。
1 安装 PostgreSQL
在深入了解 PostgreSQL 前,先得在我们得主机上安装一下 PostgreSQL。
对于 macOS 用户非常简单,使用以下命令安装
1 | brew install postgresql |
一开始我也是这么安装的,它也可以支持升级新的 PostgreSQL,是非常方便的。但是这里我更加推荐一种安装方式,使用 Docker 来安装启动 PostgreSQL,因为它可以跨平台按需使用,更加方便且易于后期修改。
关于 Docker 的安装,可以在 Docker Desktop for Mac and Windows 安装对应的客户端软件。
1 | docker run --name postgres -p 5432:5432 -v ~/Documents/docker-volumn/postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD=postgres -d postgres:12-alpine |
另外可以去PostgreSQL 官方文档多多了解 PostgreSQL,丰富的知识点在等着你们学习,下图的黄色部分尤其是重点也是难点。
2 走进 PostgreSQL 内部
2.1 组织结构
假设我们是使用 macOS 的 brew 安装的 PostgreSQL。那么数据库的文件路径应该在 /usr/local/var/postgres
下。它的目录结构如下所示
1 | # 文件 |
数据库中表和索引都是文件形式存储在磁盘上,文件名为 oid,大小最大为 1 GB,超过则会创建一个新的文件。而文件的内部被划分成一个个页,而页的大小默认为 8 KB。
那么怎样才能找到对应的文件在我们磁盘的哪个位置呢?可以利用 SQL 查询得到我们想要的结果。
1 | -- 找到数据库的 oid |
表相关的文件类型有三类,除了存储表数据的文件外,还有后缀为 _fsm
的是空闲空间映射文件,而 _vm
为可见性映射文件。值得注意的是索引文件是没有可见性映射文件的。
1 | ➜ 16401 pwd |
这里跟 MySQL 不同的一点是 MySQL 的页大小为 16 KB,而操作系统默认的页大小也为 4 KB。
2.2 堆表文件
PostgreSQL 内部采用堆元组存储数据本身,因此一个页上将会有多个元组(heap tuple),并使用元组标识符(tuple identifier,tid)来表示,其结构为(页号,行指针偏移量)
页结构
- 头部数据
- p d_lsn: 最近应用到本页面 XLog 记录的 LSN
- pd_lower: 指向行指针的末尾,空闲空间开始的位置
- pd_upper: 指向最新元组的位置,空闲空间结束的位置
- 行指针
- 长度为 15 bit
- 有偏移量,长度和标志这三个属性
- 堆元组数据
- HeapTupleHeaderData
- t_xmin:插入事务的 ID
- t_xmax:删除或更新的事务的 ID
- t_cid:命令 ID
- t_ctid:当前元组或者更新元组的 TID
- t_infomask2:属性和标志位
- t_infomask:标志位
- t_hoff:首部 + 位图 + 填充的长度
- 空值位图
- 用户数据
- HeapTupleHeaderData
2.3 内存结构
- 本地内存区域
- work_mem:工作内存,用于排序命令使用
- maintenance_work_mem:维护工作内存,主要用于自动清理和重新索引
- temp_buffers:临时缓冲,用于临时表的使用
- 共享内存区域
- shared buffer pool:表和索引的数据会加载到这里
- WAL buffer:存储事务日志
- commit log:存储事务提交日志
- 其他共享区域
缓冲区管理器
PostgreSQL 缓冲区管理器由缓冲表、缓冲区描述符和缓冲池组成,管理着共享内存和持久存储之间的数据传输。其维护缓冲区标签(数据库 oid,表 oid,文件类型分支号)到缓冲池页位置的关系,并采用时钟扫描算法(LFU 的一种变体)来进行页面置换,辅以后台的检查点进程和后台写入器进程来进行脏页刷盘。
- 缓冲表层是一个散列表,存储着页面的缓冲区标签与缓冲区描述符的缓冲 ID(同时也是缓冲池位置) 之间的映射关系,提供共享模式和独占模式的分段式、轻量级锁
- 缓冲区描述符层是一个由缓冲描述符组成的数组,每个缓冲区描述符与下层的缓冲池槽一一对应,保存着相关页面的元数据。为了加快分配过程,维护了一个空闲列表,用于快速分配下一个可用的缓存区描述符。并提供用于内容读写的共享模式和独占模式的内容锁和独占的 I/O 锁。
- 缓冲池是一个每个槽为 8 KB,用来保存页面文件数据的一个数组。
2.4 多进程架构
PostgreSQL 采用的多进程的架构,通过以下命令可以找出所有的 postgre 进程。
1 | # 先使用 ps 找到 postgres 的 ppid(上级父程序的 pid) |
PostgreSQL 默认的最大客户端连接数为 100 个,由于多进程的缘故,与 MySQL 的线程连接模型相比,其内存压力更大。
3 索引
PostgreSQL 的索引有多种类型,其中比较常见的是 B 树,而 MySQL 则使用的是 B+ 树,这是两者的一大区别。
未完待续…
更多精彩内容请关注: