文档首页/ 数据仓库服务 DWS/ 最佳实践/ 性能调优/ 在业务开发前选择合适的表类型以提高开发效率和查询性能
更新时间:2026-01-06 GMT+08:00
分享

在业务开发前选择合适的表类型以提高开发效率和查询性能

数据库的存储模型直接影响数据处理的性能与效率,本文对当前DWS支持的表类型进行介绍,从存储格式进行分类,对各种类型的表的适用场景进行介绍,并提供了一些简单的使用示例,方便业务进行表选型和开发。

表的存储格式

从数据的存储结构上看,DWS支持两种存储格式:行存,列存

需要注意的是,行列混存表本质上也是列存格式。

  • 行存表:以数据行(Row)为最小物理存储单元,同一行的所有字段在物理上相邻连续存储(包括空值占位)。可以通过行标识符tid定位到一整行的数据。

    行存表的数据物理存储示例:

    1
    2
    3
    4
    | ID  | Name  | Age | Salary | Department | 
    |-----|-------|-----|--------|------------|
    | 001 | 张三  | 30  | 15000  | 技术部     |  完整行数据连续存储
    | 002 | 李四  | 28  | 12000  | 市场部     |
    
  • 列存表:以数据列(Column)为最小物理存储单元,每列的数据连续存储,同列数据连续排列,不同列独立存储为不同的存储单元。

    列存表的数据物理存储示例:

    1
    2
    3
    Column: ID       | 001 | 002 | 003 |...
    Column: Name     | 张三 | 李四 | 王五 |...
    Column: Age      | 30 | 28 | 35 |...
    

DWS支持的表类型

目前DWS支持的表类型有:行存表,列存2.0表,Hstore_opt表,存算分离表,行列混存表

  • DWS的系统表以及业务默认创建的表都是行存表。
  • 列存2.0表,Hstore_opt表,存算分离表和行列混存表都属于列存表,这几种列存表都是以数据列存储为基础演化出来的,分别适用于不同的业务场景。

行存表介绍

行存表的一行数据可以通过一个位置指针(索引)一次找到,并且在读取时一次读取至少一整行数据。

基于以上特点,行存储的优势主要有两个方面:

  • 点查性能好:在点查场景下可以直接索引到某行数据的元组位置;
  • 更新效率高:行存储在实时并发入库,并发更新方面都比较有优势。

但是也有一些缺点:

  • 存储时空间占用大:当前DWS采用多版本保存更新前后的数据,造成脏数据也占用存储空间;
  • 读放大:读取时需要读取一整个页面和元组,如果是大宽表,但是又只读取一两列数据的情况下,读放大的问题比较严重。

对于传统的OLTP业务,数据需要进行频繁的增删改查的场景,比较适合使用行存表。

举例:

1
2
3
4
5
6
-- 默认类型,指定 ORIENTATION = ROW 或者默认即可。
CREATE TABLE table_row
(
    c1 INT,
    c2 TEXT
) WITH (ORIENTATION = ROW);

列存表介绍

行形式存储的表如果涉及到分析查询场景,特别是在数据量大且复杂的查询时,就会遇到性能瓶颈,这时可以选择列存储。

列存储的优势主要有两方面:

  • 批量查询性能好:当分析查询只涉及某列或者某几列,不需要访问无关列,特别是在表的宽度比较大时(如一千列),优势更加明显。
  • 空间占用小:列存储支持压缩,而且由于单列数据类型相同,压缩性能更高。

在OLAP场景下,优选列存表,以下按不同使用场景分别介绍列存2.0表、Hstore_opt表、存算分离表(3.0列存表)、行列混存表。

列存2.0表

列存2.0表是最初的列存表,各列数据按一定数量组成一个存取单元(CU),压缩后写入一个物理文件中,通过辅助表控制以CU为单位的事务可见性。

列存2.0表目前在已上线的各种业务中广泛使用。

举例:

1
2
3
4
5
6
-- 指定 ORIENTATION = COLUMN 选项
CREATE TABLE table_col
(
    c1 INT,
    c2 TEXT                                     
) WITH (ORIENTATION = COLUMN);

Hstore_opt表

列存2.0表虽然在海量复杂查询方面相比行存表有优势,但是也存在比较明显的短板:由于事务可见性基于CU,所以基本无法支持并发更新入库。

随着业务复杂程度的提升和实时入库+查询诉求越来越多,Hstore_opt表应运而生。Hstore_opt表融合行存和列存的优势,在列存2.0的基础上业务入库并发进行了优化:使用一个行存表存储实时的增删改操作信息,然后通过后台线程将行存表数据merge到CU中。

Hstore_opt表解决了列存2.0表的以CU为单位进行并发的问题,支持上游增删改操作实时并发入库,数据merge到CU后又保证了数据的压缩能力和分析能力。

由于近些年实时业务的需求越来越多,Hstore_opt表已逐步取代列存2.0表,成为首选的列存表类型。

举例:

1
2
3
4
5
6
-- 在列存的基础上指定 ENABLE_HSTORE_OPT = TRUE 选项
CREATE TABLE table_hstore
(
    c1 INT,
    c2 TEXT                                     
) WITH (ORIENTATION = COLUMN, ENABLE_HSTORE_OPT = TRUE);

存算分离表

Hstore_opt表解决了实时业务的问题,但是由于列存表的AppendOnly属性,实时业务中大量的并发插入或更新会导致CU文件快速膨胀,而EVS存储价格不低,所以用户成本很高。

存算分离表在Hstore_opt表的基础上将CU文件存储到OBS(华为分布式对象存储,一种高可靠、低成本的海量持久化存储产品)中,搭配本地EVS盘的diskcache缓存能力,既可以尽可能地保证读取和写入的性能,又能有效降低用户成本。同时依托OBS的分布式存储能力,可以做到存储无线扩展,计算能力快速扩缩。

对于比较重视存储成本以及弹性能力的业务,可以选择存算分离表。

举例:

1
2
3
4
5
6
7
-- 需要选择存算分离集群
-- 在hstore表的基础上增加 COLVERSION = 3.0 选项
CREATE TABLE table_v3
(
    c1 INT,
    c2 TEXT                                     
) WITH (ORIENTATION = COLUMN, ENABLE_HSTORE_OPT = TRUE, COLVERSION = 3.0);

行列混存表

列存2.0、Hstore_opt表、存算分离表虽然在批量查询、实时入库、空间管理方面都做了各种优化,但还是无法做到行存表的点查性能。行列混存表则用空间换时间,将行列格式混合存储,通过占用更多的空间来换取点查性能的提升。

行列混存表在一张表中同时存储行格式数据和列格式数据,两种格式各自独立维护、同步更新,由查询优化器根据实际查询路径选择最优访问方式,通过列存固有的过滤优化能力实现更智能的I/O路径控制,自动选择访问行/列格式数据。确保提供列存储高压缩、高吞吐优势的同时,保留行存储对局部数据的灵活访问能力。

行列混存表适用于混合查询场景下的高效数据调度。行列混存表可以显著降低整体I/O开销,同时提升数据命中率与查询性能。

举例:

1
2
3
4
5
6
-- 在hstore表的基础上增加 STORAGE_MODE = MIX 选项
CREATE TABLE table_mix
(
    c1 INT,
    c2 TEXT                                     
) WITH (ORIENTATION = COLUMN, ENABLE_HSTORE_OPT = TRUE, STORAGE_MODE = MIX);

表类型选择建议

行存储和列存储各有优势,没有绝对的优劣之分。行存储在事务处理方面表现出色,而列存储在大数据分析领域优势明显。随着技术的发展,二者的界限正逐渐模糊,现代数据库系统越来越多地采用混合策略来兼顾不同场景的需求。数据库选型时,应根据具体的应用场景、查询模式和性能要求来选择合适的存储模型。

表1 不同表类型差异

表类型

行存表

列存2.0

Hstore表

存算分离表

行列混存表

数据存储方式

以元组为单位,将每一条数据的所有属性值存储到临近的空间里。

以CU(Compress Unit)为单位,将单个属性的所有值存储到临近的空间里。

数据主要以CU形式存储在列存主表上,对于被更新的列、小批量插入的数据将被序列化后存储到新设计的Delta表上。

类似hstore表,CU文件写入到OBS中。

存储行格式数据和列格式数据。

数据写入

没有压缩能力,数据按原始状态存储,磁盘空间占用较大。

支持压缩,同一列属性值类型相同,压缩效果好。数据写入时能极大节省IO资源与磁盘空间占用。

批量插入的数据直接写入CU,具有与列存一致的压缩优势。被更新的列、小批量插入的数据会序列化后压缩。同时定期merge到主表CU。

类似hstore表,CU数据异步写入OBS。

类似hstore,数据按行/列格式同时存入CU,占用空间变大,但得益于压缩能力,空间占用比行存表小。

数据更新

数据按行更新,没有CU锁问题,并发更新(update/upsert/delete等)性能好。

即使更新单条数据,也要获取整个CU的锁,基本无法支持并发更新(update/upsert/delete等)。

彻底解决列存更新的CU锁问题,并发更新(update/upsert/delete等)的性能达到行存的60%以上。

OBS相较本地盘读写速度较慢,通过异步写方式加快写入速度。

并发更新能力与hstore表相似。

数据读取

按行读取,即使只需访问某一列的数据,也需要将一整行的数据取出。非点查性能较差。

按列读取时只需访问该列的CU,再加上CU的压缩优势导致需要占用的IO资源更少,单列读取性能很好。

对于列存主表的数据按列读取,对于被更新的列、小批量插入的数据会反序列化后取出,数据merge到主表后具有与列存一致的数据读取优势。

通过本地盘diskcache能力加速读取。

由查询优化器根据实际查询路径选择最优访问方式,通过列存固有的过滤优化能力实现更智能的I/O路径控制,自动选择访问行/列格式数据

优点

并发更新性能好,点查能力强。

查询性能好,磁盘占用空间少。

并发更新性能好,数据MERGE后具有与列存一致的查询性能优势与压缩优势。

扩缩能力强,存储成本低。

兼顾点查性能和空间压缩能力,比行存表磁盘占用小。

缺点

占用磁盘空间多,查询性能差。

基本无法支持并发更新。

需要后台常驻线程对HStore表进行merge清理操作。先merge到CU主表再进行清理,与SQL语法中的Merge无关。

OBS相较本地盘读写速度较慢。

相比列存表和hstore表,磁盘占用较高。

适用场景

更新删除操作频繁的TP事务场景。点查询(基于索引的、返回数据量小的简单查询)。

查询分析为主的AP场景。数据量大,存入后的更新删除操作少。

实时并发入库场景。需要支持高并发的更新入库操作以及高性能的查询效率。

对实时扩展性要求较高或者存储成本敏感的场景。

即要求实时入库和大数据查询分析,又要兼顾点查性能的业务。

相关文档