GBase 8c
架构原理
文章

GBase 8c 行列双存(HTAP)技术详解

发表于2026-08-11 14:12:37222次浏览1个评论

背景

企业数据库负载通常可分为两类:OLTP(联机事务处理) 与 ​OLAP(联机分析处理)) ​。OLTP 以点查、更新为主,追求高并发与低延迟;OLAP 以范围扫描、聚合统计为主,追求吞吐与分析性能。两者的访问模式差异巨大,传统数据库往往只能"二选一":

存储模式 强项 短板
纯行存 点查、更新性能优异 范围扫描与聚合效率低,如 select count(*) 需全表扫描整张表,性能非常慢
纯列存 列式扫描、聚合分析快 无法实时更新,更新性能非常差,基本无法支撑实时写入

以 PostgreSQL / openGauss 这类传统行存数据库为例,select count(*) 这类统计查询每次都要顺序扫描整张表,性能瓶颈明显;而列存虽然能彻底缓解这一缺陷,但传统列存又难以做到行级的实时更新。

核心诉求

用户希望​用一套数据库同时享有行存的高并发查询与列存的高速分析​,实现架构更简单、数据更新更实时,无需在多套系统之间搬运数据。

HTAP(Hybrid Transaction/Analytical Processing,混合事务分析处理) 正是为这一诉求而生。GBase 8c 通过行列双存机制落地 HTAP 能力。

HTAP 行列双存核心思想

行列双存也称之为 HTAP,其核心思想非常直观:

一张表​既保存行存数据,又保存列存数据​,两份数据独立存储。

  • 对于 ​TP 业务​(点查、更新)→ 走行存查询;
  • 对于 ​AP 业务​(范围查询、聚合统计,如 select count(1) from k1;)→ 走列存查询。

由此完美适配 OLTP / OLAP 混合负载场景,解决传统单一行存储模式下的性能瓶颈:

  • 行存保障高并发点查与实时更新;
  • 列存弥补行存全表扫描、聚合统计的性能缺陷;
  • 同时克服了传统列存无法实时更新的短板,保证数据更新的实时性;
  • 让客户用一套数据库即获得两种能力,架构更简单、数据更新更实时。

架构总览

GBase 8c 采用分布式架构,由 GTM 节点 + 多 CN + 多 DN 组成: image.png

节点 职责
GTM 全局事务管理器,主要提供事务 ID 等全局事务信息
CN 对外提供应用接入节点,并参与计算;不保存表数据,仅保存系统表、数据字典等元数据
DN 存储全部表数据,并承担主要的数据计算

​表数据全部保存在 DN 节点,CN 节点不持有用户数据​,这是理解后续实现的前提。

核心概念

在深入实现之前,先厘清几个关键概念:

行块(Row Block)

行存数据与列存数据的对应关系,通过对行存数据进行水平切分建立:

  • 将行存表按 1024 页为单位进行水平切分,切成一块一块的​行块​;
  • 每个行块是后续列存构建与重建的基本粒度。

Row Group 与 CU

  • 列存侧通过 Row Group 对行块进行管理,一个 Row Group 对应一个行块;
  • 行块中的每一列数据会形成一个 ​**CU(Column Unit,列单元)**​;
  • 一个组有多少列数据,就生成多少个 CU。

image.png

Delta 表

列存数据无法直接承载频繁的增删改,因此引入 Delta 表承接变化数据:

  • Delta 表保存对应行存中的行号以及该行数据属于​哪个 CU​;
  • 采用物理页级记录策略——每个物理页只要有修改,就在 Delta 表中保存一条记录,而不是为每一行记录一条;
  • 这样 Delta 表的数据量可以​减少几个数量级​,对列存 insert / update / delete 的性能影响基本可以忽略。

image.png

三张物理表

触发行列双存后,每个 DN 会创建三类表协同工作:

表 作用
列存表 保存列存数据(CU)
CU 描述表 与列存表共同构成完整列存,通过描述符寻址定位 CU
Delta 表 保存变化(增量)数据,记录哪些 CU 的哪个物理页发生了变化

pg_htap 系统表

  • CN 侧维护一个 ​pg_htap 模块​,用于保存​行列变换命令​;
  • 由于 IMCS 描述符等均为内存信息,​断电后可能丢失​,上电重启时系统会从 pg_htap 表中读取命令,恢复内存中的 cache 信息。

功能实现与效果展示

image.png

CN 侧:IMCS 描述符

  • 在 CN 上实现一个 ​IMCS 描述符​,本质是一个​哈希表​,记录哪些表已启用行列双存功能;
  • 配合 pg_htap 系统表实现命令持久化与上电恢复。

DN 侧:CU 与存储管理

DN 在 CN 功能之外,还多出 ​CU 与存储的管理​:

  • ​CU 组管理​:保存 CU 组(即一个行块)的组织关系;
  • ​CU 重建​:当增量数据积累过多时对 CU 进行重建;
  • ​CU 更新管理​:对 CU 的更新进行管理。

实现上,行列双存表涉及行存存储引擎与列存存储引擎两个存储:

  • 行存引擎基本无变化,改动很小;
  • 主要改造集中在​列存引擎​:
    • CU 部分保存在列存存储中;
    • Delta 表(变化数据)保存在行存中。

触发方式

行列双存​在建表时不指定​,而是在建表完成后,通过​命令进行触发​:

  1. 客户端下发行列双存转换命令;
  2. 命令被保存到系统表(pg_htap 模块);
  3. 上电重启后依据系统表执行恢复。

查询效果:全表扫描

以 select count(*) 为例对比执行路径:

场景 执行路径 效果
传统行存表 顺序扫描全表 性能慢
行列双存表 走​IMCstore 节点​(列存数据) 无增量修改时性能提升数倍

实测演示中,同一查询从 ​213ms 降至 23ms​。需要说明的是:如果 Delta 表中存在增量数据,实际仍可取得数倍提升,但效果不会有纯列存演示那么理想。

image.png

image.png

image.png

行列混合查询

支持​行列混合查询​——一个查询中既包含点查又包含范围查询时:

  • 范围查询部分走列存扫描;
  • 点查部分走传统索引扫描。

以上路由由数据库系统​自动完成​,无需人工干预。

关键流程介绍

1. 行列转换流程

行列双存的内部实现流程如下: image.png

  1. 客户端通过命令行方式触发转换命令;
  2. 命令经接入点 CN 向所有 CN 和 DN 广播;
  3. ​CN 节点​:创建哈希记录,标识该表具有行列双存属性,并将命令保存到系统表(pg_htap 模块);
  4. ​DN 节点​:除上述动作外,创建列存表、CU 描述表、Delta 表,然后本地多线程遍历行存表——每个线程负责分配到的物理页,扫描数据、构建 CU 并保存到列存中。

当前实现使用 9 个线程进行扫描,尽管保存 CU 环节部分操作仍需串行,整体性能依然可观:​几千万行数据大约只需几秒即可完成转换​。

2. 查询流程

image.png

  1. ​CN 生成执行计划​:检查表是否使能行列双存;
    • 若已使能,创建 ​IMCstore Scan 扫描路径​;
    • 将该路径与正常顺序扫描路径进行​代价比较​;
    • 若 IMCstore 路径代价更小,则保留该路径,最终生成 ​IMCstore 执行计划​。
  2. CN 下发执行计划到需要执行的各 DN 节点;
  3. ​DN 执行​:与传统的"列存作为数据保存容器"不同,这里的 bitmap 等特性均不适用,而是由 IMCstore 模块依据 Delta 表信息重新构建两个扫描位图:
    • ​增量数据扫描 bitmap​;
    • ​删除 bitmap​(CU 的删除位)。

对每个 CU 扫描时,分三种情况处理:

情况 说明 处理方式
CU 无效 CU 损坏;或 CU 重建期间因 MVCC 多版本导致事务不一致——描述符表保存于表内、重建在 DN 独立进行且未在 CN 层锁表,重建完成后可能仍读到旧描述符,旧描述符与新 CU 数据无法对应而报错 向行存获取完整 CU 数据
Delta 表有数据 先扫描该 CU 的 Delta 表数据,通过删除 bitmap 过滤掉已删除物理页包含的行,再扫描剩余 CU 数据 Delta 表 + CU 列存联合扫描
无 CU 记录 如新插入的数据尚未生成 CU,仅在 Delta 表有记录 向行存获取完整 CU 数据

性能退化风险 如果增删改特别多、Delta 表数据量大且 CU 数据基本被删空,查询性能会明显下降。此时需要执行 CU 重建流程:在表空闲时,从行存表重新扫描整份数据,构建完整 CU 后落盘。

3. 数据更新流程

数据更新流程(含增删改及 copy 流程)相对简单:

image.png

  1. 行存插入一行数据后,​**通知列存(HTAP 模块)**​;
  2. 判断该行对应的物理页是否已有修改记录:
    • 无修改 → 在 Delta 表中保存一条记录;
    • 已有修改 → 统计信息后直接返回,不再向 Delta 表插入数据。

​物理页级记录的效果​:假设每个物理页平均保存 100 行数据,插入 100 万行数据,Delta 表只需保存约 1 万条记录。否则 Delta 表数据体量过大会导致重建时频繁修改删除,性能急剧下降,甚至需要完整的 vacuum。

​CU 重建任务触发​:插入操作完成后,HTAP 模块统计行存表的变化情况(数据量或页数):

  • 物理页变化 ​超过 200 页​;
  • 或行数据增删变化 ​超过 3 万行​;

满足任一条件即构建一条 ​CU 重建任务​,压入任务队列,由独立的重建线程周期性地取出执行,每次重建一个表的 CU。

4. 自动 CU 重建(HTAP 关键技术)

image.png

CU 重建是 HTAP 落地的​关键核心技术​:

如果增量数据非常多而又不能及时重建,对于高并发 TP 业务,可能用不了多久,列存性能就会赶不上行存。

更深层的问题在于 ​CN 与 DN 信息不一致​:执行计划由 CN 生成,而变化数据保存在 DN 侧,CN 并不感知 DN 的增量数据情况。它单纯基于 CU 内数据评估执行计划代价,认为计划很快,实际上数据已高度劣化,按列存查询可能已经非常慢。

重建机制的设计要点:

  • ​独立任务 + 周期遍历​:单独启动任务线程,周期性遍历任务队列,逐表重建;
  • ​Try Open 机制​:为避免与表上的排它锁产生死锁,改造原有打开表的方式——​不排队、直接重试​;若重试多次仍无法打开,则将该表​扔回队列尾​,继续处理下一条;
  • ​完整锁表​:事务型数据库若不锁表,构建出的 CU 数据可能不完整、不一致,导致列存查询结果与行存差几条数据,因此重建时一定是​完整锁表​;
  • ​重建与切换​:锁表后扫描该 CU 对应的所有物理页,重新生成 CU → 删除原 CU 描述符 → 将新描述符插入 CU 描述表 → 新 CU 数据落盘。

旧描述符的处理 由于描述符与 CU 数据没有多版本概念,扫描时可能拿到旧描述符对应到​新 CU 数据​,校验必然不一致。因此扫描时会判断获取到的描述符是否为旧版本:若是,则​到行存获取数据​,不再扫描 CU。 这也正是"行列双存的优势"——​随时可以从行存获取每个 CU 的完整数据​,为 CU 重建、故障恢复提供了兜底能力。

总结与展望

核心优势

GBase 8c 行列双存(HTAP)通过"一份数据、两套存储"的设计,实现了:

  • 一套数据库搞定混合负载 — TP 点查/更新走行存,AP 范围/聚合查询走列存,自动路由、无需人工干预;
  • 架构更简单 — 无需维护两套独立系统及数据搬运链路;
  • 更新实时 — 物理页级 Delta 表机制让列存对增删改的开销基本可忽略,克服传统列存无法实时更新的短板;
  • 性能有保障 — 全表扫描等 AP 查询性能提升数倍(实测 213ms → 22ms);
  • 自愈能力强 — 自动 CU 重建 + 行存兜底,保证长期高并发 TP 写入下列存分析性能不退化的底线。

适用场景

  • 同时存在高并发事务写入与实时统计分析的混合负载业务;
  • 需要 ​TP 与 AP 数据强一致​、无法容忍 T+1 数据搬运的实时分析场景;
  • 希望以一套分布式数据库替代"OLTP 库 + OLAP 库 + ETL"组合架构的客户。

一句话总结

GBase 8c 行列双存(HTAP)= 一份数据两套存储,行存保 TP 高并发,列存提 AP 快分析,自动路由、实时更新、自动重建,一套数据库搞定 OLTP / OLAP 混合负载。

参考视频

【G 术时刻第 22 期】GBase 8c HTAP 介绍 P1-简介_哔哩哔哩_bilibili

【G 术时刻第 22 期】GBase 8c HTAP 介绍 P2-功能实现及效果展示_哔哩哔哩_bilibili

【G 术时刻第 22 期】GBase 8c HTAP 介绍 P3-关键流程_哔哩哔哩_bilibili

评论

登录后才可以发表评论
GBase用户51829发表于 2个月前
GBase 8c 行列双存(HTAP)= 一份数据两套存储,行存保 TP 高并发,列存提 AP 快分析,自动路由、实时更新、自动重建,一套数据库搞定 OLTP / OLAP 混合负载。