重新聚簇表
概述
聚簇的灵感来自于 Snowflake 中的数据聚簇和 Oracle 中的属性聚簇。
一个聚簇表根据表中某些列的值以有序的方式存储数据。聚簇有利于分区消除 和文件碎片整理。
默认情况下,数据按照自然维度存储在表中。我们需要根据聚簇键重新聚簇表。另一方面,即使聚簇表已经很好地聚簇,如果不断写入新数据,聚簇效果会随着时间的推移而变差。因此,有必要添加重新聚簇操作。
设计
有关更详细的原理和图片,请参考snowflake 自动聚簇。
对整个表进行排序的成本非常高,尤其是对于不断有新数据流入的表。为了在高效剪枝和低成本之间取得平衡,表只需要大致排序而不是完全排序。因此,在指标中引入了两个指标来确定表是否聚簇良好。重新聚簇的目标是减少overlap
和depth
。
为了避免对同一块数据进行多次聚簇,我们将块分成不同的层级,类似于 LSM 树。重新聚簇类似于 LSM 的压缩操作。level
表示该块中的数据被聚簇的次数。重新聚簇操作在同一层级上进行。
pub struct ClusterStatistics {
... ...
pub level: i32,
}
重新聚簇操作的工作流程分为两个任务:块选择和块合并。
语法
ALTER TABLE [ IF EXISTS ] <table_name> RECLUSTER [ FINAL ] [ WHERE condition ] [ LIMIT <segment_count> ]
如果指定final
,优化将一直进行,直到表聚 簇良好为止。否则,重新聚簇工作流程只会运行一次。
该语句应由表上的 DML 触发。
指标
-
overlap 与给定块重叠的块数。
-
depth 在同一位置重叠的块数。这些点从聚簇值域范围的最小值和最大值中收集。
块选择
新流入数据的初始层级为 0。我们首先关注较新的数据,换句话说,选择操作优先在层级 0 上进行。这样做的好处是减少写放大。
-
计算每个点的深度和块的重叠,并汇总得到 avg_depth。该算法已经在system$clustering_information中反映,这里不再重复。avg_depth 的理想结果是 1。为了实现大致排序,考虑定义一个阈值或比例(threshold = blocks_num * ratio)。只要 avg_depth 不大于这个阈值,该层级的块就可以被认为是聚簇良好的,然后我们在下一层级进行块选择。
-
选择深度最高的点范围(一个或多个),并选择该范围覆盖的块作为下一阶段块合并的对象集。如果存在多个深度最高的范围,可能会有多组块可以在块合并期间并行处理。
提示:
1. 聚簇键可能在表有数据时创建或更改,因此可能存在未按聚簇键排序的块。考虑在重新聚簇时暂时忽略这些块。
2. 如果一个块的聚簇键只有一个值(最大值和最小值相等,达到常量状态)且其row_num为1_000_000,将其层级设置为-1并在重新聚簇时过滤掉。
3. 选择的块可能需要考虑总大小,否则排序可能会导致内存不足。
块合并
对收集的块进行排序和合并。合并后的块超过一定阈值(1_000_000 行)后,将分成多个块。新生成的块放入下一层级。
组织块并生成新的段和快照,最后更新表元数据。如果在此时有新的 DML 执行,当前工作流程将无法提交并返回错误。我们需要考虑具体的处理流程。
选择和合并操作重复进行,直到表聚簇良好为止。