一种基于分区列谓词补偿的物化视图增量更新方法

2023-03-03 10:04:05 浏览数 (2)

背景

当前业界在做物化视图增量更新时,物化视图一般会存储在一张分区表中,以分区为粒度进行增量、刷新、删除;不然就需要生成大量的物化视图元数据或每次都要重新计算历史所有的物化数据,成本是巨大的。上述物化视图的增量为基础表数据append增加新分区,刷新为先删除后增加,删除即删除对应的分区;当前的物化视图分区表不允许有空洞,否则会导致物化视图无法命中;其他一致性问题见物化视图一致性问题。

增量物化视图的分区表是一张物理表,每次进行增量构建时,会先将数据计算好后追加load到新的分区,然后再 commit 元数据,会存在一段时间的中间状态;那么在改写用户sql时,根据当前的业界普遍的物化视图改写规则,就可能会把新分区的数据计算进去,导致数据不一致。存在一种方案是生成一张映射表,改写用户sql的时候访问映射表,映射表只会映射ready分区的数据。本文提供另一种基于谓词补偿的方法,来解决该问题。

原理

如上图[2022-01-01, 2022-01-05)是物化视图有效分区,2022-01-05这个分区在进行构建,此时物化视图如果还支持改写用户sql的话,那么可能会出现有一部分数据已经写入到2022-01-05分区,此时改写后的sql是扫描了物化视图中全部分区的数据,则数据不一致。

如上图为其中给一个解决方案,就算此时有一部分数据写入到了2022-01-05,但是命中的物化视图对应的是关联映射的表,物化视图有效分区还是[2022-01-01, 2022-01-05),2022-01-05映射的存储数据为空,读不到真实存储中的2022-01-05分区,所以此时数据一致。

谓词补偿

Q:如果不用上面的解决方案,我们是否还可以通过其他方式解决?

A:改写物化视图时,进行谓词补偿,即无论是否精确改写,都把WHERE 分区范围补充上。

在不能精确改写时,即物化视图的分区范围为 [2022-01-01, 2022-01-05),如果查询的sql取范围 [2022-01-02, 2022-01-05),则命中物化视图的部分会被改写为 SELECT * FROM mv WHERE dt >= 2022-01-02 。

精确改写时,即sql查询的范围为[2022-01-01, 2022-01-05) 改写后的sql为 SELECT * FROM mv 。

如果精确改写后的sql为 SELECT * FROM mv WHERE dt >= 2022-01-01 and dt < 2022-01-05 ,非精确改写后的sql为SELECT * FROM mv WHERE dt >= 2022-01-02 and dt < 2022-01-05,那么则不会扫描到有效分区外的数据,即只有最后元数据的更新,数据才可以被扫描,就可以保证数据一致性。即补偿谓词 dt >= 2022-01-01 和 dt < 2022-01-05 。

Q:为什么开源代码不直接做谓词补偿 ?

A:谓词补偿可能导致数据的重复计算,因为开源逻辑做的更加泛化,需要适用更多场景;例如原来已经判断过条件 name = 'jhon',增加谓词补偿后,每行数据又要判断一次name='jhon'。

Q:为什么我们要做谓词补偿?

A:因为我们进行谓词补偿的列为分区列,不需要重复计算,可以直接扫描。

Q:谓词补偿在更新历史物化视图时会有问题吗?

A: 如果用户需要刷新历史已经物化过的分区,因为只有一份存储,所以只能先下线从开始到更新的部分或者从更新部分到最后已经ready的分区,等更新完成后,再恢复。且用户在更新物化视图时,已经将查询sql促发,可能会导致该sql会扫描到在更新分区的数据。

结论

从上述说明中,我们可以发现通过指定物化视图的分区列做谓词补偿,可以解决在物化视图增量过程中的大多数问题。当然使用映射表也是一个好方案,目前业界的很多框架也是使用该设计,例如kylin的segment。

Reference

https://github.com/apache/hive/blob/6f7c55ab9bc4fd7c3d0c2a6ba3095275b17b3d2d/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/HiveMaterializedViewRule.java

https://github.com/apache/calcite/blob/b9c2099ea92a575084b55a206efc5dd341c0df62/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewRule.java

0 人点赞