Greenplum表存储模型
文章目录
1 背景
Greenplum支持行存和列存,支持堆表和AO表,那么他们有什么不同,如何选择呢?另外介绍一下压缩和非压缩表,同时如何修改表的分布,如何进行分布表的重新分布。修改表的存储类型。
2 堆表和AO表
2.1 堆表和AO表的原理
2.1.1 堆表
1、堆表,实际上就是PG的堆存储,堆表的所有变更都会产生REDO,可以实现时间点恢复。但是堆表不能实现逻辑增量备份(因为表的任意一个数据块都有可能变更,不方便通过堆存储来记录位点。) 堆表存储在OLTP类型负载下表现最好,这种环境中数据会在初始载入后被频繁地修改。 UPDATE和DELETE操作要求存储行级版本信息来确保可靠的数据库事务处理。堆表最适合于较小的表,例如维度表,它们在初始载入数据后会经常被更新。
一个事务结束时,通过clog以及REDO来实现它的可靠性。同时支持通过REDO来构建MIRROR节点实现数据冗余。
2.1.2 AO表
2、AO表,看名字就知道,只追加的存储,删除更新数据时,通过另一个BITMAP文件来标记被删除的行,通过bit以及偏移对齐来判定AO表上的某一行是否被删除。
追加优化表存储在数据仓库环境中的非规范表表现最好。 非规范表通常是系统中最大的表。 事实表通常成批地被载入并且被只读查询访问。 将大型的事实表改为追加优化存储模型可以消除每行中的更新可见性信息负担,这可以为每一行节约大概20字节。这可以得到一种更加简洁并且更容易优化的页面结构。 追加优化表的存储模型是为批量数据装载优化的,因此不推荐单行的INSERT语句。
事务结束时,需要调用FSYNC,记录最后一次写入对应的数据块的偏移。(并且这个数据块即使只有一条记录,下次再发起事务又会重新追加一个数据块)同时发送对应的数据块给MIRROR实现数据冗余。
因此AO表不适合小事务,因为每次事务结束都会FSYNC,同时事务结束后这个数据块即使有空余也不会被复用。(你可以测试一下,AO表单条提交的IO放大很严重)。
虽然如此,AO表非常适合OLAP场景,批量的数据写入,高压缩比,逻辑备份支持增量备份,因此每次记录备份到的偏移量即可。加上每次备份全量的BITMAP删除标记(很小)。
AO表,适合批量数据写入,不适合单行的insert,适合大表使用,所以一般用在数据仓库系统,适合OLAP系统.
2.2 什么时候选择堆表
当数据写入时,小事务偏多时选择堆表。
当需要时间点恢复时,选择堆表。
2.3 什么时候选择AO表
当需要列存时,选择AO表。
当数据批量写入时,选择AO表。
2.4 创建一个堆表
CREATE TABLE foo (a int, b text) DISTRIBUTED BY (a);
2.5 创建一个AO表
创建一个不带压缩的AO表
=> CREATE TABLE bar (a int, b text)
WITH (appendoptimized=true)
DISTRIBUTED BY (a);
Note: 使用appendoptimized=value语法来指定追加优化类型的表存储。 appendoptimized是appendonly传统存储选项的精简别名。 Greenplum数据库在catalog里存储appendonly,并在列出追加优化表的存储选项时显示相同的内容。
在一个可重复读或可序列化事务中的追加优化表上不允许UPDATE和DELETE,它们将导致该事务中止。追加优化表上不支持CLUSTER、DECLARE...FOR UPDATE和触发器。
3 行存和列存
Greenplum提供面向存储的模型选择:行,列或两者的组合。 本主题提供了为表选择最佳存储的一般准则。 使用您自己的数据和查询工作负载评估性能。
- 面向行的存储:适用于具有许多迭代事务的OLTP类型的工作负载以及一次需要多列的单行,因此检索是高效的。
- 面向列的存储:适合于在少量列上计算数据聚集的数据仓库负载,或者是用于需要对单列定期更新但不修改其他列数据的情况。
对于大部分常用目的或者混合负载,面向行的存储提供了灵活性和性能的最佳组合。 不过,也有场景中面向列的存储模型提供了更高效的I/O和存储。 在为一个表决定存储方向模型时,请考虑下列需求:
-
表数据的更新。
如果用户会频繁地装载和更新表数据,请选择一个面向行的堆表。
面向列的表存储只能用于追加优化表。
参考堆存储获得更多信息。
-
**频繁的插入。**如果频繁地向表中插入行,请考虑面向行的模型。列存表并未对写操作优化,因为一行的列值必须被写到磁盘上的不同位置。
-
查询中要求的列数。
如果在查询的SELECT列表或者WHERE子句中常常要求所有或者大部分列,请考虑面向行的模型。 面向列的表最适合的情况是,查询会聚集一个单一列中的很多值且WHERE或者HAVING谓词也在该聚集列上。例如:
SELECT SUM(salary)...SELECT AVG(salary)... WHERE salary > 10000或者面向列的情况是WHERE谓词在一个单一列上并且返回相对较少的行。例如:
SELECT salary, dept ... WHERE state='CA' -
**表中的列数。**在同时要求很多列或者表的行尺寸相对较小时,面向行的存储会更有效。对于具有很多列的表且查询中访问这些列的一个小子集时,面向列的表能够提供更好的查询性能。
-
**压缩。**列数据具有相同的数据类型,因此在列存数据上支持存储尺寸优化,但在行存数据上则不支持。 例如,很多压缩方案使用临近数据的相似性来进行压缩。 不过,临近压缩做得越好,随机访问就会越困难,因为必须解压数据才能读取它们。
3.1 行存和列存的原理
3.1.2 行存
1、行存,以行为形式组织存储,一行是一个tuple,存在一起。当需要读取某列时,需要将这列前面的所有列都进行deform,所以访问第一列和访问最后一列的成本实际上是不一样的。
在这篇文档中,有deform的详细介绍。《PostgreSQL 向量化执行插件(瓦片式实现) 10x提速OLAP》
行存小结:
全表扫描要扫描更多的数据块。
压缩比较低。
读取任意列的成本不一样,越靠后的列,成本越高。
不适合向量计算、JIT架构。(简单来说,就是不适合批处理形式的计算)
需要REWRITE表时,需要对全表进行REWRITE,例如加字段有默认值。
3.1.3 列存储
2、列存,以列为形式组织存储,每列对应一个或一批文件。读取任一列的成本是一样的,但是如果要读取多列,需要访问多个文件,访问的列越多,开销越大。
列存小结:
压缩比高。
仅仅支持AO存储(后面会将)。
读取任意列的成本是一样的。
非常适合向量计算、JIT架构。对大批量数据的访问和统计,效率更高。
读取很多列时,由于需要访问更多的文件,成本更高。例如查询明细。
需要REWRITE表时,不需要对全表操作,例如加字段有默认值,只是添加字段对应的那个文件。
3.2 什么时候选择行存
如果OLTP的需求偏多,例如经常需要查询表的明细(输出很多列),需要更多的更新和删除操作时。可以考虑行存。
3.3 什么时候选择列存
如果OLAP的需求偏多,经常需要对数据进行统计时,选择列存。
需要比较高的压缩比时,选择列存。
如果用户有混合需求,可以采用分区表,例如按时间维度的需求分区,近期的数据明细查询多,那就使用行存,对历史的数据统计需求多那就使用列存。
3.4 创建一个列存储表
CREATE TABLE命令的WITH子句指定表的存储选项。默认是面向行的堆表。使用面向列的存储的表必须是追加优化表。例如,要创建一个列存表:
=> CREATE TABLE bar (a int, b text)
WITH (appendoptimized=true, orientation=column)
DISTRIBUTED BY (a);
4 压缩(只适用于追加优化表)和非压缩
4.1 压缩的方式
对于追加优化表,在Greenplum数据库中有两种类型的库内压缩可用:
- 应用于一整个表的表级压缩。
- 应用到一个指定列的列级压缩。用户可以为不同的列应用不同的列级压缩算法。
4.2 压缩的算法
下面的表总结了可用的压缩算法。
| 表方向 | 可用的压缩类型 | 支持的算法 |
|---|---|---|
| 行 | 表 | ZLIB, ZSTD和 QUICKLZ1 |
| 列 | 列和表 | RLE_TYPE, ZLIB, ZSTD和 QUICKLZ1 |
Note: 1QuickLZ压缩在Greenplum数据库的开源版本中不可用。
4.3 压缩因素
在为追加优化表选择一种压缩类型和级别时,要考虑这些因素:
-
CPU使用。用户的Segment系统必须具有可用的CPU能力来压缩和解压数据。
-
压缩率/磁盘尺寸。最小化磁盘尺寸是一个因素,但也要考虑压缩和扫描数据所需的时间和CPU计算能力。要找到能高效压缩数据但不导致过长压缩时间或者过慢扫描率的最优设置。
-
压缩的速度。与zlib比较,QuickLZ在较低的压缩率下通常使用较少的CPU计算能力、能更快地压缩数据

本文深入解析Greenplum数据库的存储模型,包括堆表、AO表、行存、列存的区别及适用场景,以及压缩技术的选择和应用。通过实际测试对比不同存储方式的性能差异,帮助读者理解如何优化数据存储。
最低0.47元/天 解锁文章
467

被折叠的 条评论
为什么被折叠?



