运算符如何增量刷新¶
下表概述了每个运算符的增量方式(即如何将其转换为生成更改而不是完整结果的新查询片段)、其性能,以及其他需要考虑的重要因素。
运算符 |
增量 |
注意事项 |
---|---|---|
SELECT <scalar expressions> |
通过将表达式应用于已更改的行实现递增。 |
表现良好,没有需要注意的特殊事项。 |
WHERE <scalar expressions> |
通过计算每个已更改行上的谓词实现递增,仅包括谓词为 true 的行。 |
总体表现良好。成本随变化大小线性增长。 使用高度选择性的 WHERE 表达式刷新动态表可能需要仓库正常运行时间,即使生成的动态表没有变化。这是因为可能需要仓库来确定源中的哪些更改满足谓词。 |
FROM <base table> |
通过扫描上次刷新以后添加到表或从表中移除的微分区来实现递增。 |
成本随添加或移除的微分区中的数据量线性增长。 建议:
|
<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;
上述语句可以优化如下: CREATE DYNAMIC TABLE intermediate
AS
SELECT date_trunc(minute, ts) ts_min, c1 FROM table;
CREATE DYNAMIC TABLE sums
AS
SELECT ts_min, sum(c1) FROM intermediate
GROUP BY 1;
|
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,以此实现递增。然后递增此分解查询。 内部联接递增如下所示。通过检查在一端的变更键是否在另一端已经存在,来实现不存在值的递增。 |
建议:
|
LATERAL FLATTEN |
通过对更改的行应用展平运算符实现递增。 |
总体表现良好。成本随变化大小线性增长。与 FROM <base table> 运算符相同的一般注意事项。 |