GaussDB行存储表列存储表相关
表存储方案
行存储、列存储的建表语句
表的行/列存储通过表定义的orientation属性定义。当指定orientation属性为row时,表为行存储;当指定orientation属性为column时,表为列存储;如果不指定,默认为行存储
行存储(默认存储)建表语句
CREATE TABLE table_name
(
……
)WITH(orientation=row)
注:create table默认为行存储,故WITH(orientation=row)可省略不写
列存储建表语句
CREATE TABLE table_name
(
……
)WITH(orientation=column)
列存表的数据存储原理
列存表的最小存储单元是CU(Compress Unit),每个CU的大小为8KB的整数倍(需要注意的是,CU并不是由页组成的,它是一个独立的存储单元),最多存储1列60000行数据。同一列的多个CU连续存放在一个数据文件中,当数据文件的大小超过1G,会自动切换到新的文件中。
除此之外,每个列存表还有一个记录CU的辅助和管理信息的行存表CUDesc表,该表中的每一行记录对应一个CU,包括最大值/最小值、数据条数,以及CU在文件中的偏移量及大小。其中,col_id=-10的行为VCU, cu_pointer记录这一组CU(cu_id相同)中哪些行被删除。另外,CU的可见性也是通过CUDesc的可见性来决定的。
当在列存表上导入数据时,首先数据会按列导入CU cache,如果设置了PCK(Partial Cluster Key),导入数据会按照指定列进行局部排序(默认420万条数据进行排序),最后再生成CU(生成CU时,会根据数据类型进行压缩),并写入文件。列存表推荐使用批量方式导入数据,如insert into select/copy、GDS、SQL on Hadoop/OBS等,这样可以充分利用CU空间,以及使用PCK索引。单行数据插入会产生较多的小CU文件,不但会造成空间浪费,还会导致访问效率降低。因此对于列存表的数据导入,强烈推荐使用批量方式
分区的分类和使用场景
范围分区(Range Partitioning)、列表分区(List Partitioning)、哈希分区(Hash Partitioning)、间隔分区(Interval Partitioning)等,分区键支持整型、字符型、时间型等数据类型。
建立分区表时的注意事项
1.小表扫描本身耗时不大,分区表的性能收益不明显,因此只建议对大表采取分区策略。列存储模式下因为每个列是单独的文件出处,且最小的存储单元CU可存储6w行数据,因此对于列存分区表,建议每个分区的数据不小于DN个数*6w
2.将分区上边界的分区值定义为 MAXVALUE,以防止可能出现的数据溢出。
参考语句:
CREATE TABLE web_returns_p1
(
wr_returned_date_sk integer,
wr_returned_time_sk integer,
wr_item_sk integer NOT NULL,
wr_refunded_customer_sk integer
)
WITH (orientation = column)
DISTRIBUTE BY HASH (wr_item_sk)
PARTITION BY RANGE(wr_returned_date_sk)
(
PARTITION p2016 START(20161231) END(20191231) EVERY(10000),
PARTITION p0 END(maxvalue)
);
3.由于分区表是把逻辑上的一张表根据范围分区策略分成几张物理块库进行存储,这张逻辑上的表称之为分区表,物理块称之为分区。而物理存储数据时为不同物理存储区域,所以查询数据时需要通过分区键进行区域定位,否则会扫描所有区域的数据表,性能会不如单表全量查询。
一般使用具有明显区间性的字段进行分区,比如日期、区域等字段上建立分区。
分区查询时,当where语句中的分区键包含函数或隐式类型转换时,无法进行分区剪枝,也就是说where查询中的分区键一般只有跟常量值存在直接的比较(>、<、=、<=、>=)操作时,分区表才可以正常剪枝。
4.由于分区表是逻辑上的一张表,但是物理为多个存储分区,所以分区表过多会导致分区和统计信息增加,内存和磁盘开销会增大,所以分区表及分区不是越多越好。
内容参考来源
https://zhuanlan.zhihu.com/p/271720614
https://www.modb.pro/db/22158
https://www.modb.pro/db/408902