跳到主要内容
版本:2.x

数据分布与倾斜

Apache Cloudberry 依赖于跨 Segment 的均匀数据分布。

在 MPP(大规模并行处理)的无共享(shared nothing)架构中,一个查询的总体响应时间取决于所有 Segment 的完成时间。整个系统的速度取决于最慢的那个 Segment。如果数据发生倾斜,拥有更多数据的 Segment 将需要更长的时间来完成任务。因此,每个 Segment 都必须拥有大致相等的行数,并执行大致相同的处理工作量。如果某个 Segment 需要处理的数据量远超其他 Segment,就可能导致性能下降和内存不足的情况。

在连接(join)大表时,优化的分布至关重要。要执行连接操作,匹配的行必须位于同一个 Segment 上。如果数据没有按照相同的连接列进行分布,那么其中一个表所需的行就会被动态地重新分发到其他 Segment。在某些情况下,系统会执行广播(broadcast motion)操作,即每个 Segment 将其各自的行发送给所有其他 Segment;而不是执行重分布(redistribution motion)操作,即每个 Segment 对数据进行重新哈希计算,并根据哈希键将行发送到相应的 Segment。

本地连接(Co-located Join)

使用哈希分布将表行均匀地分布到所有 Segment,并实现本地连接,可以带来显著的性能提升。当要连接的行位于同一个 Segment 上时,大部分处理都可以在该 Segment 实例内部完成。这种连接被称为“本地连接”或“同位连接”(co-located join)。本地连接可以最大限度地减少数据移动;每个 Segment 独立于其他 Segment 运行,无需网络流量或 Segment 间的通信。

要为经常连接的大表实现本地连接,你需要将这些表按照相同的列进行分布。本地连接要求连接操作的两端都按照相同的列(并以相同的顺序)进行分布,并且分布子句中的所有列都在连接表时被使用。分布列还必须是相同的数据类型——尽管某些不同数据类型的值可能看起来表示相同,但它们的存储方式不同,哈希值也不同,因此它们会被存储在不同的 Segment 上。

数据倾斜

数据倾斜可能是由于选择了错误的分布键,或执行了单行插入(single tuple insert)或复制操作,从而导致数据分布不均。数据倾斜发生在表级别,通常是查询性能不佳和内存不足问题的根本原因。倾斜的数据不仅影响扫描(读取)性能,还会影响所有其他的查询执行操作,例如连接(join)和分组(group by)操作。

在初次加载数据后,验证分布以确保数据均匀分布,这一点非常重要。同样重要的是,在增量加载后要持续验证分布情况。

以下查询显示了每个 Segment 的行数,以及行数的最大值和最小值之间的差异:

SELECT 'Example Table' AS "Table Name", 
max(c) AS "Max Seg Rows", min(c) AS "Min Seg Rows",
(max(c)-min(c))*100.0/max(c) AS "Percentage Difference Between Max & Min"
FROM (SELECT count(*) c, gp_segment_id FROM facts GROUP BY 2) AS a;

gp_toolkit 模式(schema)提供了两个视图,你可以用它们来检查数据倾斜。

  • gp_toolkit.gp_skew_coefficients 视图通过计算存储在每个 Segment 上的数据的变异系数(CV)来显示数据分布的倾斜情况。skccoeff 列显示了变异系数(CV),其计算方法是标准差除以平均值。它同时考虑了数据序列的平均值和围绕平均值的变异性。这个值越低越好,值越高表示数据倾斜越严重。
  • gp_toolkit.gp_skew_idle_fractions 视图通过计算表扫描期间系统空闲时间的百分比来显示数据分布的倾斜情况,这是计算倾斜的一个指标。siffraction 列显示了在表扫描期间系统空闲时间的百分比。这个指标反映了数据分布不均或查询处理倾斜的情况。例如,值 0.1 表示 10% 的倾斜,值 0.5 表示 50% 的倾斜,依此类推。倾斜度超过 10% 的表,应该重新评估其分布策略。

关于复制表的注意事项

当你创建一个复制表(使用 CREATE TABLEDISTRIBUTED REPLICATED 子句)时,Apache Cloudberry 会将表的每一行分发到每一个 Segment 实例。复制表的数据是均匀分布的,因为每个 Segment 都拥有相同的行。如果你尝试在一个复制表上使用 gp_segment_id 系统列来验证数据是否均匀分布,查询将会失败,因为 Apache Cloudberry 不允许查询引用复制表的系统列。

处理倾斜

当过多的数据流入并由一个或少数几个 Segment 处理时,就会产生处理倾斜。它通常是 Apache Cloudberry 性能和稳定性问题的罪魁祸首。它可能发生在连接(join)、排序(sort)、聚合(aggregation)以及各种 OLAP 操作中。处理倾斜发生在查询运行过程中,不像数据倾斜那么容易检测。

如果只是单个 Segment(而不是主机上的所有 Segment)出现故障,这可能就是处理倾斜问题。目前,识别处理倾斜仍然是一个手动过程。首先要查找溢出文件(spill files)。如果存在倾斜,但程度不足以导致文件溢出,它通常不会成为性能问题。一旦你确定存在倾斜,下一步就是找出导致倾斜的查询。

几乎所有情况下,处理倾斜的解决方法都是重写查询。创建临时表可以消除倾斜。临时表可以被随机分布,以强制执行两阶段聚合。