存储管理决定了数据如何组织、更新和清理,直接影响数据库的空间效率和吞吐稳定性。本文整理 GaussDB 两种存储引擎(Ustore / Astore)的对比,以及页式、段页式两种文件管理方式的适用场景。
一、Ustore 与 Astore
GaussDB 提供两种存储引擎,核心区别在于更新方式 和历史版本的存放位置:
| 对比项 | Ustore | Astore |
|---|---|---|
| 更新方式 | 原地更新(引入 ITL 区域) | 追加写(先删后插) |
| 历史版本 | 集中存放在 Undo 区域 | 与活跃数据混合存储 |
| 空间/性能 | 垃圾清理效率高,空间和吞吐较平稳 | 插入效率高,清理开销大,容易空间膨胀 |
| 适用场景 | 更新频繁 | 插入频繁 |
记忆口诀 :U 更新稳,A 插入快;U 的旧版本进 Undo,A 的新旧版本混在一起。
补充几个细节:
- Ustore 通过 ITL 区域指向 undo record 和事务槽位,实现原地更新。
- Astore 的
UPDATE= 先删(旧元组置 t_xmax)后插新元组。 - 索引的
UPDATE同样不是原地覆盖,而是旧索引元组失效后再插入新索引元组。
二、页式文件管理
页式管理是最基础的文件组织方式:
- 数据文件按 1GB 固定大小切分为物理文件,文件名由
relfilenode标识。 - 单个数据文件最大可达 32TB。
页式管理的适用场景是:数据库对象数量少、数据规模较小。
它不适合以下场景,因为这些场景会产生大量物理文件,文件句柄过多会影响全量重建、备份等操作:
- 分布式 HashBucket 场景;
- 10 万级大分区表;
- 数据库对象数量非常多;
- 数据规模很大。
三、段页式存储
段页式是一种更灵活的空间管理方式,采用"段空间 → Datafile → Segment → Extent → Page"的层级结构。
3.1 不支持的存储对象
段页式不支持以下六类对象,需要重点记忆:
- 列存表
- 外表
- 内存表
- 压缩表
- 序列
- 物化视图
记忆口诀 :列、外、内、压、序、物。 普通的行存表可以使用段页式存储。
3.2 补充约束
- 段页式的扩展步长固定为 128MB。
- 支持
SHRINK SPACE收缩空间,但不能收缩 1 号数据文件。
四、WAL 与 XLOG
WAL(Write-Ahead Logging,先写日志再写数据)是保证事务持久性的关键机制:
wal_buffers表示存放 WAL 数据的共享内存空间,其单位是XLOG_BLCKSZ的块数。XLOG_BLCKSZ默认大小为 8KB。
一个容易误解的点:wal_buffers 不是越大越好。因为每次事务提交都会将 WAL 缓冲区内容写盘,设置得很大并不一定能显著提高性能。
WAL 段文件大小为 16MB,Redo 文件的最大占用可以通过公式估算:
(wal_keep_segments + checkpoint_segments × 2 + 1) × 16MB
五、页面结构
以 Astore 为例,数据页面的组成包括:
- Page Header(页头):约 40 字节,包含页面 LSN、Checksum、空闲空间起止偏移。
- Line Pointer(行指针):每条 4 字节。
- Tuple Header(元组头):Astore 为 24 字节,Ustore 为 12 字节。
- Tuple Data(元组数据):实际数据。
对于索引页,special 区域保存访问方法元数据(如 B-tree 层级、左右兄弟页和标志),而索引的真实键值存放在索引元组中,不在 special 区域。
小结
- Ustore 原地更新、历史版本进 Undo,适合更新频繁;Astore 追加写、新旧版本混存,适合插入频繁。
- 页式按 1GB 切片,适合对象少、规模小;段页式不支持"列、外、内、压、序、物"。
XLOG_BLCKSZ默认 8KB,wal_buffers不是越大越好。- 页面/元组头等字节数:页 8KB、Astore 元组头 24B、Ustore 元组头 12B、行指针 4B。