HTAP 行列融合

可获得性

本特性自 openGauss 7.0.0-RC1 版本开始引入。

特性简介

HTAP 行列融合特性在单机、主备场景下,通过节点的行列双格式内存模式,实现openGauss HTAP一体化数据库架构。 通过高效的行列转换技术方案,节点读取磁盘行存数据,生成列存储单元(Column Unit)存储至节点的列缓存中;支持节点通过代价估算生成列缓存查询计划,通过列存查询大幅提升复杂OLAP场景下的数据分析效率,使数据库同时具备较强的TP和AP能力。在主备场景下,列缓存数据均存储在备节点,通过日志读取回放,同步主节点在OLTP场景下大量的行数据变更,以维持列缓存数据的新鲜度。

图 1 主备场景行列转换特性设计方案

客户价值

随着企业数字化变更深入,实时的高并发事务处理及复杂的数据整合、分析混合工作负载成为企业数据库的核心诉求。业务系统逐步通过HTAP(Hybrid Transactional/Analytical Processing)数据库的模式升级来响应新的业务场景,即通过同一套数据库内存系统,同时支持高效的事务处理(OLTP)和复杂查询(OLAP)。

openGauss 通过简单的指令设置,有效利用备节点可用内存空间进行行存数据的列缓存转换及存储(In-Memory-Column-Store)。考虑列存的查询优势,在数据量庞大,表结构复杂,而用户仅关注部分列数据的查询的场景下,行列转换后的列缓存可有效提升企业执行大型复杂OLAP数据分析的整体查询效率。

特性描述

openGauss主备集群场景下,支持备节点形成行列双格式内存形式。针对主节点的行级修改,备节点通过日志同步主节点修改,将对应修改写入增量表中。同时,备节点后台启动的同步线程,将增量表中存储的行存修改同步至列存缓存中。用户在备节点发起的OLAP大型数据分析请求,将先通过逻辑判断是否已有查询表的列缓存数据,并根据代价计算形成基于列缓存的查询计划。

  • 行列数据转换:

    用户在主节点发送针对表数据的行列转换请求,将通过网络通道将指令传输至备节点;备节点根据指令信息初始化增量表,并行读取行存数据,形成基础列存储单元(Column Unit),批量插入申请的列存内存中。

  • 基于日志的行列数据同步:

    在不影响主节点行存数据修改效率的同时,为了保障备节点列缓存数据的实时性,设计备节点基于日志读取回放行存修改,以增量表及后台同步线程的方式进行列缓存数据的更新。

  • 支持列缓存的扫描查询:

    新增In-Memory-CStore-Scan (IMCStore scan)列缓存查询算子,基于openGauss执行优化器及代价估算,生成包含列缓存查询算子的向量化执行计划。

特性增强

无。

特性约束

HTAP 行列融合的规格约束如下:

  • 表:仅支持普通表的行列转换,临时表、系统表、Toast表、Unlogged表、列存表、外表暂不支持,主备场景下不支持段页式表的行列转换。

  • 数据类型:参考列存表支持的数据类型。特别地:

    • 不支持长度未知的数据类型,如:text、hll、cidr等类型。
    • 不支持长度超过 8kb 的可变长度数据库类型,如:char(2500)、varchar(2500)。不建议转换较长长度的数据类型的列。
  • 其他

    • 当前仅在单数据库下支持行列转换。
    • 轻量版 openGauss 不支持 HTAP 行列融合特性。
    • 主备场景下,由主节点发起行列转换请求,所有备节点均执行行列转换,主节点不存储列缓存。
    • 主备场景下,主节点引起的数据修改,在备节点通过列缓存查询存在一定延迟。
    • 当前不支持重新行列转换,已经转换的表/分区需要先取消行列转换后,再重新行列转换。
    • 转换分区表时,若指定某个分区行列转换,仅支持指定一级分区,若指定一级分区下存在二级分区,默认自动行列转换。
    • 已行列转换的表,不支持 truncate 表、修改列名/列属性、增加/删除列、修改表压缩参数操作。特别地,已经转换的分区表,不支持新增、删除、交换、清空、分割、合并、移动、重命名操作。
    • 对于间隔分区表,自动新增的分区,当前不会自动行列转换。
    • 当前 DB 已转换的表,不支持 VACUUM FULL 操作。
  • 主备场景下,需要修改主备节点的pg_hba.conf认证方式,以允许行列转换请求传输(这里的值取决于实际的网络配置以及用于连接的用户):

host     all     dbuser     primary_ip/32     trust
host     all     dbuser     standby_ip/32     trust

依赖关系

向量化引擎

使用指导

HTAP 行列融合特性支持用户针对全表、表指定列、指定分区进行行列转换及清除已有列缓存操作。

  • 对指定行表进行行列转换

    • 转换方式1:全表转换

      ALTER TABLE table_name IMCSTORED;
      
    • 转换方式2:表部分列转换

      ALTER TABLE table_name IMCSTORED(column_name_list);
      
    • 转换方式3:对分区表的指定分区转换

      ALTER TABLE table_name MODIFY PARTITION partition_name IMCSTORED;
      
    • 转换方式4:对分区表的指定分区的部分列转换,支持不同分区转换不同列

      ALTER TABLE table_name MODIFY PARTITION partition_name IMCSTORED(column_name_list);
      
  • 清除已转换的列缓存

    • 清除方式1:对指定行表做全量列缓存清除
      ALTER TABLE table_name UNIMCSTORED;
      
    • 清除方式2:对分区表的指定分区做列缓存清除
      ALTER TABLE table_name MODIFY PARTITION partition_name UNIMCSTORED;
      

参数说明

  • table_name

    要转换的表名。

  • column_name_list

    指定表中要行转列的字段名列表,如 (name, age)。

  • partition_name

    要转换的分区名。

示例

对已创建的行存表进行行列转换。例如:

--创建普通表
openGauss=# CREATE TABLE test
(
  id   INT,
  name VARCHAR2(40),
  dept_id    INT
);

CREATE TABLE

--对该表进行行列转换
openGauss=# ALTER TABLE test IMCSTORED;
ALTER TABLE

--查询该表,执行行存计划
openGauss=# EXPLAIN SELECT * FROM test;
                       QUERY PLAN                        
---------------------------------------------------------
 Seq Scan on test  (cost=0.00..16.01 rows=601 width=106)
(1 row)
--开启列存扫描计划
openGauss=# SET enable_imcsscan=on;
SET

--查询该表,执行列存计划
openGauss=# EXPLAIN SELECT * FROM test;
                             QUERY PLAN                             
--------------------------------------------------------------------
 Row Adapter  (cost=10.60..10.60 rows=601 width=106)
   ->  IMCStore Scan on test  (cost=0.00..10.60 rows=601 width=106)
(2 rows)

--对该表清除列缓存
openGauss=# ALTER TABLE test UNIMCSTORED;
ALTER TABLE

--对该表部分列进行行列转换
openGauss=# ALTER TABLE test IMCSTORED(id);
ALTER TABLE
--创建分区表
openGauss=# CREATE TABLE test_partition
(
  id   INT,
  name VARCHAR2(40),
  dept_id    INT,
  age  INT
) PARTITION BY RANGE(dept_id) SUBPARTITION BY RANGE (age) 
(
    PARTITION dept_id_p1 VALUES LESS THAN (5) (
        SUBPARTITION age_sub_p1 VALUES LESS THAN (25),
        SUBPARTITION age_sub_p2 VALUES LESS THAN (35),
        SUBPARTITION age_sub_p3 VALUES LESS THAN (maxvalue)
    ),
    PARTITION dept_id_p2 VALUES LESS THAN (maxvalue) (
        SUBPARTITION age_sub_p4 VALUES LESS THAN (25),
        SUBPARTITION age_sub_p5 VALUES LESS THAN (35),
        SUBPARTITION age_sub_p6 VALUES LESS THAN (maxvalue)
    )
);

CREATE TABLE

--对该表进行全量行列转换,即所有分区、所有列
openGauss=# ALTER TABLE test_partition IMCSTORED;
ALTER TABLE

--对该表清除列缓存
openGauss=# ALTER TABLE test_partition UNIMCSTORED;
ALTER TABLE

--对该表 dept_id_p1 分区的所有列进行行列转换
openGauss=# ALTER TABLE test_partition MODIFY PARTITION dept_id_p1 IMCSTORED;
ALTER TABLE

--对该表 dept_id_p1 分区清除列缓存
openGauss=# ALTER TABLE test_partition MODIFY PARTITION dept_id_p1 UNIMCSTORED;
ALTER TABLE

--对该表 dept_id_p1 分区的 id, name 列进行行列转换
openGauss=# ALTER TABLE test_partition MODIFY PARTITION dept_id_p1 IMCSTORED(id, name);
ALTER TABLE

--对该表 dept_id_p2 分区的 name, age 列进行行列转换
openGauss=# ALTER TABLE test_partition MODIFY PARTITION dept_id_p2 IMCSTORED(name, age);
ALTER TABLE

--开启列存扫描计划
openGauss=# SET enable_imcsscan=on;
SET

--查询该表 dept_id_p1 分区的 id, name 列, 执行列存计划
openGauss=# EXPLAIN SELECT id, name FROM test_partition PARTITION(dept_id_p1);
                                          QUERY PLAN                                           
-----------------------------------------------------------------------------------------------
 Row Adapter  (cost=5.58..5.58 rows=583 width=102)
   ->  Vector Partition Iterator  (cost=0.00..5.58 rows=583 width=102)
         Iterations: 1, Sub Iterations: 3
         ->  Partitioned IMCStore Scan on test_partition  (cost=0.00..5.58 rows=583 width=102)
               Selected Partitions:  1
               Selected Subpartitions:  ALL
(6 rows)

--查询该表 dept_id_p2 分区的 name, age 列, 执行列存计划
openGauss=# EXPLAIN SELECT name, age FROM test_partition PARTITION(dept_id_p2);
                                          QUERY PLAN                                           
-----------------------------------------------------------------------------------------------
 Row Adapter  (cost=5.58..5.58 rows=583 width=102)
   ->  Vector Partition Iterator  (cost=0.00..5.58 rows=583 width=102)
         Iterations: 1, Sub Iterations: 3
         ->  Partitioned IMCStore Scan on test_partition  (cost=0.00..5.58 rows=583 width=102)
               Selected Partitions:  2
               Selected Subpartitions:  ALL
(6 rows)

--查询整张表 id, name 列, dept_id_p2 未转换 id 列, 执行行存计划
openGauss=# EXPLAIN SELECT name, age FROM test_partition;
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Partition Iterator  (cost=0.00..15.83 rows=583 width=102)
   Iterations: 2, Sub Iterations: 6
   ->  Partitioned Seq Scan on test_partition  (cost=0.00..15.83 rows=583 width=102)
         Selected Partitions:  1..2
         Selected Subpartitions:  ALL
(5 rows)

--查询整张表 name 列, dept_id_p1、dept_id_p2 均转换 name 列, 因此执行列存计划
openGauss=# EXPLAIN SELECT name FROM test_partition;
                                          QUERY PLAN                                           
-----------------------------------------------------------------------------------------------
 Row Adapter  (cost=10.58..10.58 rows=583 width=98)
   ->  Vector Partition Iterator  (cost=0.00..10.58 rows=583 width=98)
         Iterations: 2, Sub Iterations: 6
         ->  Partitioned IMCStore Scan on test_partition  (cost=0.00..10.58 rows=583 width=98)
               Selected Partitions:  1..2
               Selected Subpartitions:  ALL
(6 rows)
意见反馈
编组 3备份
    openGauss 2025-04-26 22:53:55
    取消