recluster table
概述
聚类受到Snowflake中的数据聚类和Oracle中的属性聚类启发。
聚簇表根据表中某些列的值以有序的方式存储数据。聚类有利于分区消除和文件碎片整理。
默认情况下,数据按照自然维度存储在表中。我们需要根据聚类键对表进行重新聚类。另一方面,即使聚簇表已经很好地聚类,如果不断写入新数据,聚类效果会随着时间的推移而变差。因此,有必要添加重新聚类操作。
设计
有关更详细的原理和图片,请参阅snowflake auto clustering。
对整个表进行排序的成本非常高,尤其是对于不断有新数据流入的表。为了在高效剪枝和低成本之间取得平衡,表只需要大致排序而不是完全排序。因此,在指标中引入了两个指标来确定表是否聚类良好。重新聚类的目标是减少overlap
和depth
。
为了避免对同一块数据进行多次搅动,我们将块分成不同的层次,类似于LSM树。重新聚类类似于LSM的压缩操作。level
表示该块中的数据被聚类的次数。重新聚类操作在同一层次上进行。
pub struct ClusterStatistics {
... ...
pub level: i32,
}
重新聚类操作的工作流程分为两个任务:块选择和块合并。
语法
alter table [if exists] tbl_name recluster [final] [where condition]
如果指定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执行,当前工作流程将无法提交并返回错误。我们需要考虑具体的处理流程。
选择和合并操作重复进行,直到表聚类良好为止。