
# 使用DWS行列共存表
#### 场景介绍
在实际业务场景中，一张表往往既需要支持高并发的点查与更新（如订单、账单、日志等），也需要支持高效的批量查询与聚合分析（如统计报表、趋势分析）。传统的行存与列存各有所长：
- **行存（Row Store）**：适合点查、写入频繁的实时场景，如根据订单号查询订单详情。
- **列存（Column Store）**：适合大批量分析型查询，如统计一段时间内的总交易额。
DWS提供的**行列共存表** （也称行列混存表），是一种创新的混合存储模式：**在一张表中同时存储行格式数据和列格式数据，两种格式各自独立维护、同步更新，由查询优化器根据实际查询路径选择最优访问方式。**
其核心优势在于：
- **无需拆表或复制数据**：一张表即同时支持明细查询与批量分析。
- **由系统自动选择最优路径**：查询点查字段时走行存，查询聚合字段时走列存，无需额外开发处理。
- **性能最优兼顾**：在不牺牲OLTP性能的同时，兼具OLAP查询效率。
- **兼容原有行表设计**：无需调整应用结构，快速享受列存优化/行存优化带来的性能收益。
- **统一管理、降低运维成本**：一张物理表即覆盖两种场景，简化数据同步、备份与权限控制。
本最佳实践文档将介绍如何设计使用行列共存表结构，结合典型场景和性能对比，帮助您在业务系统中实现更高效的数据处理能力。
#### 实时场景下表类型对比（行存表 / 列存表 / 行列共存表）
表1实时场景下表类型对比 
| 对比维度      | 行存表（orientation='row'）                                                                                     | HStore表（hstore_opt表）                                                                                       | 行列共存表（storage_mode='mix'）                                                                                  |
|:---|:---|:---|:---|
| 存储架构      | 原生行存引擎（不基于列存）                                                                                              | HStore_opt列存                                                                                               | 自研行模式和列存HStore_opt表共存                                                                                      |
| 点查性能（主键）  | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475521077.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475481709.png "点击放大") 较差（2） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475539141.png "点击放大") 优（4）  |
| 批量入库性能    | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475539129.png "点击放大") 较差（2） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442099178.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475618965.png "点击放大") 优（4）  |
| 实时入库性能    | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442259050.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442099174.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475618961.png "点击放大") 极优（5） |
| 聚合/分析性能   | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442249484.png "点击放大") 差（1）  | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442259046.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475539133.png "点击放大") 极优（5） |
| 空间占用      | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475539137.png "点击放大") 高（1）  | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442099170.png "点击放大") 极低（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442242196.png "点击放大") 一般（3） |
| 空间膨胀      | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475618957.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442259042.png "点击放大") 极优（5） | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442099166.png "点击放大") 优（4）  |
| DWS列存特殊优化 | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002475529849.png "点击放大") 不支持   | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442258846.png "点击放大") 支持    | ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002442259054.png "点击放大") 支持    |
   
 #### 约束限制
- **仅9.1.1.100及以上版本支持**。
- 需使用HStore表，即enable_hstore_opt参数设置为开。
- 不支持物化视图。
- 小批量的实时copy入库，相比HStore表，存在10%的性能劣化。
- 行列混存表只能和行列混存表进行exchange，扩容重分布后，禁止使用exchange。
- 行列混存表执行 DROP COLUMN后，被删除列仍会占用系统列号资源，因此表的可用列数上限仍受1600列限制。
 
#### 使用建议
- **仅OLTP场景（例如高频点查、写入）**：若对空间使用敏感，推荐使用行列共存表，兼顾空间与点查性能的折中方案，若空间不敏感，追求极致效果的场景推荐行存表。
- **仅OLAP场景（例如统计分析、报表）**：推荐使用HStore的列存表。
- **明细与统计查询并存，且字段冷热难以区分**：推荐使用行列共存表模式，各个场景性能最优。
- 实时入库上，推荐使用PBE AddBatch方式入库。
- 建议不要轻易修改列定义，若触发数据重写，行列共存表会重写行存部分整个数据，性能开销较大。
 
#### 语法参考
以下是创建行列共存表语法，更多请参见[CREATE TABLE](https://support.huaweicloud.com/sqlreference-911-dws/dws_06_0177.html)语法章节（**仅9.1.1.100及以上版本支持**）。
```
CREATE TABLE <表名> (
    <列定义>
)
WITH (
    orientation = column,          -- 基于列式的存储架构
    enable_hstore_opt = on,        -- 开启 hstore_opt 能力
    storage_mode = 'mix'           -- 指定建立行列共存表
);
```
**示例**：
```
-- 行列共存模式：同时存储行格式与列格式数据，适用于明细+分析混合业务
CREATE TABLE tbl_mix (
    a INT,
    b TEXT
)
WITH (
    orientation = column,
    enable_hstore_opt = on,
    storage_mode = 'mix'
);
```
#### 使用行列混存表示例
1. 建立一个简单的数据表。 
   ```
   DROP TABLE IF EXISTS data;
   CREATE TABLE data(a INT, b BIGINT, c VARCHAR(10), d VARCHAR(10));
   INSERT INTO data values(generate_series(1,100),1,'asdfasdf','gergqer');
   ```
   
   
2. 扩充表数据至20W。 
   ```
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   INSERT INTO data SELECT * FROM data;
   SELECT COUNT(*) FROM data;
   ```
   ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002470176793.png "点击放大")
   
   
3. 构造一个简单的行列共存表。 
   ```
   DROP TABLE IF EXISTS rowmode_test1;
   CREATE TABLE rowmode_test1 (
       a INT,
       b BIGINT,
       c VARCHAR(10),
       d VARCHAR(10)
   )
   WITH (
       orientation = column,
       enable_hstore_opt = on,
       storage_mode = 'mix'
   );
   ```
   
   
4. 将数据导入行列共存表。 
   ```
   INSERT INTO rowmode_test1 SELECT * FROM data;
   ```
   
   
5. 建立视图查询cudesc的辅助表，通过自定义函数实现。 
   ```
   DROP FUNCTION IF EXISTS get_cudesc_data_info;
   CREATE FUNCTION get_cudesc_data_info(target_table_name text)
   RETURNS TABLE (
       col_id int, 
       cu_id oid, 
       min text, 
       max text, 
       row_count int, 
       cu_mode int, 
       size bigint, 
       cu_pointer text, 
       magic int, 
       extra text, 
       src_info text, 
       xid xid, 
       dr_bucket_id int, 
       dict_key bytea, 
       cu_data bytea,
       cu_data_size_kb numeric
   ) AS
   $$
   DECLARE
       cudesc_relid oid;
       cudesc_relname text;
       query text;
   BEGIN
       SELECT relcudescrelid INTO cudesc_relid FROM pg_class WHERE relname = target_table_name;
       SELECT relname INTO cudesc_relname FROM pg_class WHERE oid = cudesc_relid;
       IF cudesc_relname IS NULL THEN
           RAISE NOTICE 'CU descriptor table not found for %.', target_table_name;
           RETURN;
       END IF;
       query := FORMAT('SELECT *, octet_length(cu_data)::numeric/1024 AS cu_data_size_kb FROM cstore.%I', cudesc_relname);
       RETURN QUERY EXECUTE query USING target_table_name;
   END;
   $$ LANGUAGE plpgsql;
   ```
   
   
6. 查询DN节点名称。
   
   ```
   SELECT * FROM pgxc_node;
   ```
   ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002470195825.png "点击放大")
   查看返回信息，记录DN1对应的node_name，例如dn_6001_6002。
   
   
7. 直连DN1查询记录。其中datanode1替换成[6]查到的结果，例如dn_6001_6002。
   
   ```
   EXECUTE DIRECT ON(datanode1) $$
   SELECT col_id, cu_id, row_count, size, cu_pointer
   FROM (
       SELECT col_id, cu_id, row_count, size, cu_pointer
       FROM get_cudesc_data_info('rowmode_test1') where col_id = -16 and cu_id = 1002
   )
   $$;
   ```
   结果示例如下：
   ![](https://support.huaweicloud.com/bestpractice-dws/figure/zh-cn_image_0000002436600822.png "点击放大")
   
   
上述结果示例是行存部分，在列存辅助表中记录的示例数据，系统会在列存的辅助表中为每组 RowGroup 插入一条特殊标识记录，其字段含义如下：
- col_id：固定为 -16，用于标识该记录对应的是RowGroup元信息，而非普通列数据。
- cu_id：与列存的 CU 编号规则一致，表示该组RowGroup归属于的 CU ID。
- row_count：表示当前 CU Group 中总共包含的行数，如示例中为 60000 行。
- size：记录这些行经过压缩后的实际磁盘占用空间（单位为字节）。
- cu_pointer：该字段存储了 RowGroup 的结构信息，由四个由 \| 分隔的字段组成：
  1. 版本号：当前为1，表示该 RowGroup 使用的元数据版本。
  
  2. 单组行数：每个RowGroup中包含的最大行数（如 2000）。
  
  3. 组数：表示该CU中包含的 RowGroup 数量（如 30）。
  
  4. 起始偏移：该组 RowGroup 在物理存储文件中的起始偏移地址（如 0）。
   
总体而言，自研行存部分通过与 CU 架构的深度绑定，充分继承了列存引擎在执行优化和压缩管理方面的优势，在维持优异点查性能的同时，显著降低了空间占用，为混合型负载提供了高性价比的解决方案。
#### 行列共存表相关GUC参数
表2行列共存表相关GUC参数 
| 参数                                                                                        | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                | 默认值 |
|:---|:---|:---|
| [row_group_rows_threshold](https://support.huaweicloud.com/devg-911-dws/dws_04_0936.html) | 用于控制行列混存表row模式/mix模式行存的压缩单元行数，即指定行数压缩为一个行存压缩单元row group。 - 0表示由DWS自动选择最优值，压缩单元行数为200\~2000。  - 大于0时由用户指定压缩单位，压缩单元行数为200\~10000，若小于200仍按照200处理。   | 0   |
   
