一、 HTAP基础理论知识
-
OLTP(联机事务处理)
面向业务交易,典型场景是订单新增、修改、删除、用户提交业务单据。特点:短事务、单次操作数据量很小、并发高,对响应延迟、数据一致性要求严格。存储优先选用行存储,一条完整业务记录连续存放,单行增删改效率高。 -
OLAP(联机分析处理)
面向统计分析、报表、多维查询。典型场景:统计月度销售额、按维度聚合业务数据。特点:单次查询扫描大量数据,以读为主,大量分组、求和、计数聚合运算;对单行修改要求低。传统方案使用列存储,同一字段的数据集中存放,做聚合的时候只读取需要的字段,减少IO开销。 -
HTAP(混合事务分析处理,Hybrid Transaction‑Analytical Processing)
传统架构中OLTP和OLAP两套引擎割裂:交易库只适合业务,分析库靠ETL同步数据,会带来数据延迟、维护链路复杂。
HTAP的目标就是在同一套数据库内核中同时支持OLTP事务写入更新 + OLAP分析查询,业务数据写入之后,分析查询可以直接读取最新数据,不需要额外做数据搬迁。
HTAP常见两种实现路线:
- 双副本模式:数据库内部自动维护行存、列存两份数据,事务写入行存,分析读取列存副本,由数据库内部完成同步;
- 行列融合存储:一套存储框架下,行存、列存数据物理共存,支持列存也可以做事务性增删改,不需要维护完整双副本。
注意:HTAP不等于列存表一定比行存表快,它是架构能力,实际性能会受数据量、访问模式、内存命中率影响。
二、底层存储布局
登录disql,查看数据库为HTAP准备的底层存储对象:
SELECT name, type$, status$ FROM v$tablespace;
LINEID NAME TYPE$ STATUS$
1 SYSTEM 1 0
2 ROLL 1 0
3 TEMP 2 0
4 MAIN 1 0
type$=1代表永久表空间,type$=2是临时表空间;status$=0代表状态ONLINE,这部分行为和DM8保持一致。
SELECT TABLESPACE_NAME, CONTENTS, STATUS FROM DBA_TABLESPACES;SELECT TABLESPACE_NAME, CONTENTS, STATUS FROM
LINEID TABLESPACE_NAME CONTENTS STATUS
1 SYSTEM PERMANENT ONLINE
2 ROLL UNDO ONLINE
3 TEMP TEMPORARY ONLINE
4 MAIN PERMANENT ONLINE
SELECT * FROM V$HUGE_TABLESPACE;
LINEID ID NAME PATHNAME DIR_NUM COPY_NUM SIZE_MODE
1 4 MAIN /dmdata/data/DM9/HMAIN 1 NULL NULL
V$HUGE_TABLESPACE视图,MAIN表空间挂载了HMAIN目录/dmdata/data/DM9/HMAIN,这就是HUGE列存表实际存放数据的物理路径。
列存数据实际依托HUGE表、HMAIN目录来存放。

三、创建行存表与列存表
达梦列存表使用CREATE HUGE TABLE语法。我创建结构完全一样的一张普通行表、一张列存表,灌入相同数据(50万)做对比测试。
完整建表和插入数据SQL:
CREATE TABLE orders_row(oid INT, cust_id INT, status CHAR(1), amount DECIMAL(12,2), odate DATE, remark VARCHAR(200));
CREATE HUGE TABLE orders_col(oid INT, cust_id INT, status CHAR(1), amount DECIMAL(12,2), odate DATE, remark VARCHAR(200)) STORAGE(SECTION(65536), FILESIZE(64), WITH DELTA);
INSERT INTO orders_row SELECT LEVEL, MOD(LEVEL,1000), CHR(65+MOD(LEVEL,26)), LEVEL*1.5, TO_DATE('2026-01-01','YYYY-MM-DD')+MOD(LEVEL,365), 'remark '||LEVEL FROM DUAL CONNECT BY LEVEL<=500000;
COMMIT;
INSERT INTO orders_col SELECT oid,cust_id,status,amount,odate,remark FROM orders_row;
COMMIT;

各项操作耗时统计:
| 操作 | 耗时 |
|---|---|
| 建普通行表 orders_row | 60.313 ms |
| 建列存表 orders_col | 9.447 ms |
| 行表插入50万行 | 238.890 ms |
| 列存表插入50万行 | 311.335 ms |
四、确认列存数据真实物理位置
两张表建好之后,确认列存表数据到底存在哪里:
SELECT TABLE_NAME, TABLESPACE_NAME FROM USER_TABLES WHERE TABLE_NAME IN ('ORDERS_ROW','ORDERS_COL');
LINEID TABLE_NAME TABLESPACE_NAME
1 ORDERS_ROW MAIN
2 ORDERS_COL MAIN
SELECT COUNT(*) FROM orders_row;
COUNT(orders_row): 500000
SELECT COUNT(*) FROM orders_col;
COUNT(orders_col): 500000

从数据字典看,行表和列存表逻辑上都归属MAIN表空间。但逻辑归属不等于物理存放位置,我到操作系统层面查看HMAIN目录:
du -sh /dmdata/data/DM9/HMAIN;
26M /dmdata/data/DM9/HMAIN
ls -lh /dmdata/data/DM9/HMAIN
drwxr-xr-x 3 dmdba dinstall 21 Sep 5 13:03 SCH150994945

HMAIN目录占用26M,内部子目录SCH150994945创建时间正好是我往列存表导入数据的时刻。
由此可以确认:行存数据存放在MAIN表空间的数据文件中;列存HUGE表的数据,物理上独立保存在HMAIN目录下面。
行存、列存共处同一个数据库实例,不需要跨库迁移数据,这就是官方说的行列融合存储在存储层的具体实现。
五、TP、AP业务混跑测试
HTAP的核心价值,就是同一套实例里面,交易业务和分析业务可以同时运行。我在库中交替执行OLTP单行事务操作,以及OLAP聚合查询。
OLTP单行事务测试SQL:
INSERT INTO orders_row VALUES(999999,1,'A',100.5,SYSDATE,'tp');
COMMIT;
UPDATE orders_row SET amount=amount+1 WHERE oid=999999;
COMMIT;
DELETE FROM orders_row WHERE oid=999999;
COMMIT;

TP操作耗时:
| TP操作 | 耗时 |
|---|---|
| 单行INSERT | 4.155 ms |
| 单行UPDATE | 15.641 ms |
| 单行DELETE | 16.239 ms |
接下来做分组聚合分析查询,每条SQL执行两次,取稳定耗时:
SELECT cust_id, COUNT(*), SUM(amount) FROM orders_row GROUP BY cust_id; -- 行表
SELECT cust_id, COUNT(*), SUM(amount) FROM orders_col GROUP BY cust_id; -- 列存表
由于内容太长,无法进行截图,把结果列到表中。
| 操作 | 第1次 | 第2次 |
|---|---|---|
| 行表分组聚合 | 63.926 ms | 75.684 ms |
| 列存表分组聚合 | 84.415 ms | 75.089 ms |
测试结果:在分组聚合场景,列存表性能和行表几乎持平,第一次执行甚至更慢。
分析背后的原因:
- 本次50万行全部可以加载进数据库内存缓冲区,查询瓶颈在CPU计算、SQL解析,而不是磁盘IO。列存储“只读需要的列、压缩减少IO”的优势发挥不出来;
- 两张表都是全表扫描,数据全部命中内存buffer,存储带来的差异被抹平;
- 第一次执行包含硬解析开销,所以两次执行耗时存在波动。
这个实测结果:小数据量、全部数据命中内存、没有索引的场景,列存不一定执行的更快。
六、验证列存的列投影优势
列存储最核心的优势就是列投影:查询只需要读取用到的字段,不用读取整行所有字段。对amount字段做求和,再次对比性能。
SELECT SUM(amount) FROM orders_row; -- 行表,跑两次
SELECT SUM(amount) FROM orders_row;
SELECT SUM(amount) FROM orders_col; -- 列存表,跑两次
SELECT SUM(amount) FROM orders_col;

| 操作 | 第1次 | 第2次 |
|---|---|---|
| 行表单列SUM | 50.344 ms | 51.455 ms |
| 列存单列SUM | 9.572 ms | 8.007 ms |
只做单字段求和,列存表性能大概是行表的6倍。
原理:列存只读取amount这一列压缩数据块;而行存储读取一条记录,会把一整行全部字段读到内存,再提取amount字段。数据量上来后,列存能够大幅降低IO读取量,这就是列投影的实际效果。
七、HTAP落地使用总结
结合理论和本次单机实测,对DM9 HTAP可以得到几个实操层面的判断:
-
存储架构:逻辑统一,物理隔离
行存表和列存表,字典层面都归属MAIN表空间;但列存HUGE表实际物理数据独立保存在HMAIN目录。同一个实例中行存、列存并存,不需要把数据同步到另外一套数据库,这就是“行列融合存储”的落地形态。 -
列存性能有明确的触发条件,不是万能加速神器
小数据量、数据全在内存中,列存优势并不明显,分组聚合甚至和行存差不多。
当满足数据量大 + 查询只访问少数字段 + 查询会触发磁盘IO读取,列存的压缩、列投影优势才能体现出来,本次单列SUM测试达到约6倍性能差距。不能不管业务场景,无脑把业务表全部改成列存。 -
业务选型建议
频繁单行新增、修改、删除的交易业务表,优先选择行存;
以扫描、聚合统计为主的大表,很少单行更新,适合用WITH DELTA的HUGE列存表。行表列表可以部署在同一个DM9实例中,实现HTAP。
如果业务规模继续扩大,部署DMDPC分布式集群,再叠加子计划级并行计算、负载均衡,才是完整HTAP能力。




