写点什么

OLAP 分析型应用场景中,数仓中 vacuum 为何对列存表无效

  • 2022 年 6 月 20 日
  • 本文字数:1691 字

    阅读完需:约 6 分钟

本文分享自华为云社区《GaussDB(DWS)中vacuum为何对列存表无效?【这次高斯不是数学家】》,作者: i 云上小白。


在 OLAP 分析型应用场景中,列式存储有十分明显的优势,相比行式存储,其高压缩比、高 I/O 效率及批量数据运算的特性极大提升了统计分析查询的效率。虽然存储模式不同,对列存表进行频繁的插入(insert)和更新(update)操作仍然会导致空间膨胀问题,实际上在很多时候,往往不建议对列存表进行数据更新和非批量方式的数据插入。


基于 GaussDB(DWS)的 mvcc 机制,行存表在删除、更新数据时会保留原来的旧数据,这些数据我们称之为死元组(dead tuple)。频繁地对行存表执行删除和更新操作会导致数据页中产生大量的死元组,不但使存储空间膨胀,而且降低了对表的查询效率。针对这一现象,GaussDB(DWS)采用 vacuum 机制来清除不需要的死元组及索引,释放空间。但对于列存表来说,vacuum 是无效的,必须使用 vacuum full 才能有效回收空间。


当然对行存表执行 vacuum 回收空间是有限的,在某些情况下 vacuum 后的表大小甚至不会有丝毫变化。这是因为如果删除的记录位于表的末端,其所占用的空间将会被物理释放并归还操作系统,而如果不是末端数据,会将表中或索引中 dead tuple 所占用的空间置为可用状态,从而复用这些空间。


对列存表执行 vacuum 为什么是无效的呢?其实这与列存表的存储结构以及数据写入方式有关。


从下图中可知,列存表的最小存储单元是 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 文件,不但会造成空间浪费,还会导致访问效率降低。因此对于列存表的数据导入,强烈推荐使用批量方式。



下面我们看看列存表上的删除和更新操作是如何进行的。


在列存表上进行 delete 时,首先会根据删除条件找到需要删除的行 ctid(cu_id,offset),然后对需要删除的行 ctid 去重(每 420 万行排序去重),最后在行对应的 VCU 的 delete map 上打上删除标记。至于 update 操作,实际上是一个 delete+insert(append)操作。首先根据更新条件找到更新的行,打上删除标记(ctid 需去重),然后将原来整行更新相应数据后,插入到新 CU 中。


对行存表来说,数据页中的每个元组都占用了一块独立的空间,每个元组有一个行指针,记录了这个元组的状态。当执行 update 或者 delete 操作后,死元组的行指针 lp_flags 的状态会被标记为 3: LP_DEAD,即死亡状态,等待 vacuum 清理。倘若执行了 vacuum,指针状态会被标记为 0: LP_UNUSED,即未使用状态,表示该元组占用的空间可以被复用。



虽然列存表可以像行存表那样对被删除或者更新前的数据进行标记,但由于 CU 中的数据是按列连续存放的,CU 生成数据后固定不可更改。如果使用指针对每一个数据位的状态进行标记,其代价较大(行指针长度几乎等于数据长度,同时 I/O 开销巨大),而且数据写入 CU 采用的是追写(append)方式,即便死元组被标记为可复用状态,也无法再使用这些空间。


另外,列存表的读取是以 CU 为单位,真正影响列存表性能的是 CU 文件数量,而 vacuum 即便可以回收死元组占用的空间,却不能合并小 CU 文件。因此,对列存表来说,vacuum 是无效的。此时,可以使用 vacuum full 整理 CU 碎片,合并小 CU 文件,提升性能。


点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 3
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
OLAP分析型应用场景中,数仓中vacuum为何对列存表无效_数据库_华为云开发者联盟_InfoQ写作社区