深入理解 openGauss 的 Ustore 存储引擎

新员工技术分享

2025年10月


为什么需要 Ustore?

  • 传统 Heap 表的问题
    • 更新 = 删除旧 tuple + 插入新 tuple(写放大)
    • 多版本导致空间膨胀,依赖 vacuum
  • Ustore 的目标
    • 支持 原地更新(in-place update)
    • 使用 Undo Log 实现 MVCC
    • 减少空间浪费,提升 OLTP 性能

什么是 Ustore?

  • openGauss 中的 新型行存储格式

  • 创建方式:

    CREATE TABLE t1 (c1 int, c2 int) 
    WITH (storage_type=ustore, init_id=32);
    
  • 核心特点:

    • 每行固定位置,通过 TD(Transaction Descriptor) 管理状态
    • 使用全局 Undo Zone 存储历史版本
    • 支持高效回滚与快照读

核心数据结构

结构 作用
UHeapPageHeaderData 页面头,含 td_count、空闲空间等
TD 事务描述符,存 xactid + undo_record_ptr
UHeapDiskTupleData 磁盘 tuple,含 td_idxid 偏移
UHeapTupleData 内存 tuple 表示
UndoRecord / UndoZone 全局 Undo 管理

页面布局:Header → TD 区(最多 128 个)→ Tuple 区


INSERT 流程关键步骤

  1. UHeapamTupleInsertUHeapInsert
  2. UHeapPrepareInsert:准备 tuple
  3. RelationGetBufferForUTuple:获取 8KB page
  4. UHeapPageReserveTransactionSlot
  • 查找可用 TD
  • 无可用则尝试复用(已提交/回滚)
  • 必要时扩展 TD 区(16→32→+2→128)
  1. UHeapPrepareUndoInsert:准备 Undo 记录
  2. RelationPutUTuple:写入 tuple 到 page
  3. InsertPreparedUndo:写入 Undo
  4. LogUHeapInsert:记录 WAL

Undo 机制详解

  • Undo 存储在 全局 Undo Zone
  • 每个事务通过 t_thrd.ustore_cxt.urecvecURecVector)管理 Undo 记录
  • 流程:
    • PrepareUndoRecord:计算所需空间
    • AllocateUndoSpace:从 UndoZone 分配空间
    • urecvec->GetUndoBufidx:获取 buffer(缓存或从 nodefile 加载)
    • InsertPreparedUndo:写入 Undo page
  • TD 中记录 undo_record_ptr,用于 MVCC 回溯

事务槽(TD)管理策略

  • 每页最多 128 个 TD
  • 扩展规则:
    • <16 → 翻倍
    • <32 → 扩到 32
    • ≥32 → 每次 +2,上限 128
  • 复用条件:
    • 已提交且无活跃快照
    • 已回滚
  • 更新时复用原 tuple 位置,仅更新 TD 和 Undo

Ustore vs Heap 表对比

特性 Heap 表 Ustore 表
更新方式 插入新版本 原地更新
空间膨胀 严重(需 vacuum) 轻微(Undo 可回收)
MVCC 实现 多版本 tuple 单版本 + Undo 回溯
适合场景 OLAP / 读多写少 OLTP / 高频更新
Undo 管理 显式 Undo Log

调试与开发建议

  • 启用 Ustore:

    CREATE TABLE ... WITH (storage_type=ustore);
    
  • 关键调试点:

    • td_count 扩展逻辑
    • urecvec 中 Undo 分配
    • UHeapPageSetUndo 写入 undo_record_ptr
  • 日志级别:DEBUG1 可查看 Undo/事务槽信息

  • 源码路径:

    • src/include/access/ustore/
    • src/backend/access/ustore/

总结

  • Ustore 是 openGauss 面向 高性能 OLTP 的创新存储引擎
  • 通过 原地更新 + Undo MVCC 解决 Heap 表痛点
  • 适合高频更新、低空间膨胀场景
  • 动手建议:建表 → 插入 → 更新 → 查看 Undo 行为!

Q & A

欢迎提问!

用户 SQL UHeapamTupleInsert UHeapInsert Page Manager Undo Manager INSERT INTO t1 VALUES (1,1) 调用主插入流程 RelationGetBufferForUTuple() 返回 8KB Page (含 Header + TD + Free) UHeapPageReserveTransactionSlot() 返回可用 td_id(可能触发 TD 扩展) UHeapPrepareUndoInsert() PrepareUndoRecord() AllocateUndoSpace() → 从 UndoZone 分配 GetUndoBufidx() → 获取 undo buffer 准备好 UndoRecord UHeapTupleHeaderSetTDSlot(td_id) RelationPutUTuple() → 写入 tuple 到 page InsertPreparedUndo() → 写入 undo page UHeapPageSetUndo(td_id, undo_ptr) LogUHeapInsert() → WAL 日志 插入完成 用户 SQL UHeapamTupleInsert UHeapInsert Page Manager Undo Manager
Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐