逻辑存储结构
PostgreSQL逻辑存储结构
PostgreSQL的逻辑存储结构由多个层次组成,从数据库实例到具体的表数据文件,以下是主要组成部分:
数据库集群(Database Cluster)
一个PostgreSQL实例称为数据库集群,包含多个数据库。集群通过initdb命令初始化,生成基础目录结构(如PGDATA)。
数据库(Database)
每个数据库是逻辑隔离的单位,用户通过CREATE DATABASE创建。数据库之间默认无法直接访问对方对象(除非使用dblink扩展)。
模式(Schema)
模式是数据库内的命名空间,用于组织表、视图等对象。默认模式为public,可通过CREATE SCHEMA创建新模式。
表(Table)
表是数据存储的基本单元,由行和列组成。PostgreSQL支持:
- 普通表(持久化)
- 临时表(会话或事务级临时)
- 非日志表(UNLOGGED,不写WAL)
表空间(Tablespace)
表空间定义数据的物理存储位置,允许将不同对象分散到不同磁盘。语法示例:
sql
CREATE TABLESPACE fastspace LOCATION '/ssd/pg_data';
存储文件布局
数据文件存储在PGDATA/base目录(默认表空间):
- 每个数据库对应
base/<dboid>子目录 - 每个表对应一个或多个文件(以OID命名,如
12345) - 大表会被分割为多个文件(后缀如
.1,.2)
系统目录
PostgreSQL使用特殊的系统表存储元数据:
pg_class:存储所有关系(表、索引等)信息pg_attribute:记录表的列定义pg_database:集群中的数据库列表
事务与MVCC
PostgreSQL通过多版本并发控制(MVCC)实现事务隔离:
- 每行包含
xmin(创建事务ID)和xmax(删除事务ID) - 旧版本数据通过VACUUM机制清理
索引结构
支持多种索引类型:
- B-tree(默认,适合范围查询)
- Hash(等值查询)
- GiST/SP-GiST(地理空间数据)
- GIN(全文搜索、JSONB)
- BRIN(块范围索引)
示例:查看表文件路径
sql
SELECT pg_relation_filepath('my_table');
1 表文件内部结构
在PostgreSQL中,将保存在磁盘中的块称为Page,而将内存中的块称为Buffer,表和索引称为Relation,行称为Tuple,数据的读写是以Page为最小单位,每个Page默认大小为8kB,在编译PostgreSQL时指定的BLCKSZ大小决定Page的大小。每个表文件由多个BLCKSZ字节大小的Page组成,每个Page包含若干Tuple。对于I/O性能较好的硬件,并且以分析为主的数据库,适当增加BLCKSZ大小可以小幅提升数据库性能。
2 数据检索访问方法
当从数据库中检索数据时有两种典型的访问方法,顺序扫描和B树索引扫描 。顺序扫描通过扫描每个页面中的所有行指针顺序读取所有页面中的所有元组。B树索引扫描时,索引文件包含索引元组,每个元组由索引键和指向目标堆元组的TID组成。如果找到了正在查找的键的索引元组,PostgreSQL使用获取的TID值读取所需的堆元组。
3 进程结构

PostgreSQL是一用户一进程的客户端/服务器的应用程序。数据库启动时会启动若干个进程,其中有postmaster(守护进程)、postgres(服务进程)、syslogger、checkpointer、bgwriter、walwriter等辅助进程。
postmaster(守护进程)
postmaster 是 PostgreSQL 的主控进程,负责监听客户端连接请求并管理其他子进程的生命周期。启动数据库时,postmaster 首先初始化共享内存和关键数据结构,随后派生其他辅助进程。客户端连接请求到达时,postmaster 会为每个连接创建一个独立的 postgres 服务进程。

postgres(服务进程)
每个客户端连接对应一个独立的 postgres 进程,负责处理该连接的所有 SQL 查询和事务操作。这种"一用户一进程"的架构隔离了不同会话的资源,但会消耗较多内存。postgres 进程解析 SQL、生成执行计划、访问共享缓冲区,并将结果返回给客户端。
syslogger(系统日志进程)
syslogger 集中管理 PostgreSQL 的日志输出。默认情况下,所有进程的日志会重定向到 syslogger,由它统一写入日志文件(如 postgresql.log)。支持按时间或大小滚动日志文件,并可通过配置调整日志级别和格式。
checkpointer(检查点进程)
checkpointer 定期执行检查点(checkpoint),将共享缓冲区中的脏页(修改过的数据页)刷入磁盘,并更新控制文件以标记一致状态。检查点触发条件包括时间间隔(checkpoint_timeout)、WAL 文件切换或手动命令(CHECKPOINT)。检查点减少崩溃恢复时需重放的 WAL 日志量。
bgwriter(后台写入进程)
bgwriter 负责在检查点之间将脏页逐步写入磁盘,减轻检查点的 I/O 压力。通过算法(如 LRU)预测未来需要的页面,提前清理缓冲区空间。参数 bgwriter_delay 控制其唤醒频率,bgwriter_lru_maxpages 限制每次写入的页数。
walwriter(WAL 写入进程)
walwriter 专用于将 WAL(Write-Ahead Log)缓冲区的内容刷新到磁盘的 WAL 文件。WAL 日志是崩溃恢复的关键,确保事务的持久性。walwriter 通过批量写入减少磁盘 I/O,参数 wal_writer_delay 调整其工作频率。
其他辅助进程
- autovacuum launcher/workers:自动清理(autovacuum)进程,回收死元组空间并更新统计信息。
- stats collector:收集数据库活动的统计信息(如表扫描次数、索引使用情况)。
- archiver :在归档模式下(
archive_mode=on),将已切换的 WAL 文件复制到归档目录。 - replication :流复制场景下的
walsender和walreceiver进程,负责主从数据同步。
每个进程通过协同工作确保数据库的高可用性、数据一致性和性能优化。配置参数可通过 postgresql.conf 调整,进程状态可通过 pg_stat_activity 和系统工具(如 ps)监控。
4 内存结构
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中保存事务的状态,并将这些状态保留在共享内存缓冲区中,在整个事务处理过程中使用。
图5-9显示了内存的结构概貌。
