运算符如何增量刷新

下表概述了每个运算符的增量方式(即如何将其转换为生成更改而不是完整结果的新查询片段)、其性能,以及其他需要考虑的重要因素。

运算符

增量

注意事项

SELECT <scalar expressions>

通过将表达式应用于已更改的行实现递增。

表现良好,没有需要注意的特殊事项。

WHERE <scalar expressions>

通过计算每个已更改行上的谓词实现递增,仅包括谓词为 true 的行。

总体表现良好。成本随变化大小线性增长。

使用高度选择性的 WHERE 表达式刷新动态表可能需要仓库正常运行时间,即使生成的动态表没有变化。这是因为可能需要仓库来确定源中的哪些更改满足谓词。

FROM <base table>

通过扫描上次刷新以后添加到表或从表中移除的微分区来实现递增。

成本随添加或移除的微分区中的数据量线性增长。

建议:

  • 将每次刷新的更改量限制在源表的 5% 左右。

  • 注意会影响许多微分区的 DMLs。

<query> UNION ALL <query>

通过取两边更改并集实现递增。

表现良好,没有需要注意的特殊事项。

WITH <CTE list> <query>

通过计算每个常用表表达式的更改实现递增。

WITH 使复杂的查询更容易阅读,但注意不要使单个动态表的定义过于复杂。有关更多信息,请参阅 和 优化复杂动态表的增量刷新模式性能

标量汇总

标量汇总目前没有实现有效递增。当其输入发生变化时,会完全重新计算。

GROUP BY <keys>

通过重新计算每个更改的分组键的汇总来实现递增。

确保源数据按分组键聚类,并且更改占分组键的一小部分(大约 <5%)。

如果分组密钥包含复合表达式而不是基础列,增量刷新可能必须扫描大量数据。要减小这些扫描的大小,则在一个动态表中 具体化 表达式,然后在另一个动态表中对具体化列应用分组操作。

例如,以下面的复合语句为例:

CREATE DYNAMIC TABLE sums
  AS
    SELECT date_trunc(minute, ts), sum(c1) FROM table
    GROUP BY 1;
Copy

上述语句可以优化如下:

CREATE DYNAMIC TABLE intermediate
  AS
    SELECT date_trunc(minute, ts) ts_min, c1 FROM table;
Copy
CREATE DYNAMIC TABLE sums
  AS
    SELECT ts_min, sum(c1) FROM intermediate
    GROUP BY 1;
Copy

DISTINCT

相当于没有聚合函数的 GROUP BY ALL。

通常代表着实质性的优化机会。

常见做法是在整个查询中自由应用 DISTINCT,以避免意外引入重复项。在增量刷新中,DISTINCT 操作会周期性地消耗资源,因为每次刷新都必须检查重复项。

优化性能时,查找和删除冗余 DISTINCTs 可以轻松取胜。您可以通过消除更上游的重复项并谨慎考虑加入基数来实现。

<fn> OVER <window>

通过重新计算每个更改的分区键的窗口函数实现递增。

确保查询中有 PARTITION BY 子句,并且源数据按分区键聚类。还要确保更改占分区的一小部分(大约 <5%)。

<left> INNER JOIN <right>

通过将左侧的变更联接到右侧,然后将右侧的变更联接到左侧来实现递增。

如果联接的一侧很小,性能很可能不错。如果联接的一侧频繁变更,则通过联接键对另一侧进行聚类可能会提高性能。

<left> [{LEFT | RIGHT | FULL }] OUTER JOIN <right>

通过因子分解成一个内部联接 union-all-ed 与一到两个 NOT EXISTS 来计算非匹配的 NULLs,以此实现递增。然后递增此分解查询。

内部联接递增如下所示。通过检查在一端的变更键是否在另一端已经存在,来实现不存在值的递增。

建议:

  • 如果联接的一侧频繁变更,则通过联接键对另一侧进行聚类可能会提高性能。

  • 将频繁变更的表放在左侧。

  • 尽量减少 OUTER 对侧的变更。因此,对于 LEFT OUTER,尽量减少右侧的变更。

  • 对于 FULL 联接,位置非常重要。

LATERAL FLATTEN

通过对更改的行应用展平运算符实现递增。

总体表现良好。成本随变化大小线性增长。与 FROM <base table> 运算符相同的一般注意事项。

语言: 中文