了解动态表刷新

动态表内容基于特定查询的结果。当动态表所基于的基础数据发生变更时,该表将会更新以反映这些变更。这些更新称为 刷新。此过程是自动化的,并且涉及到分析表的基础查询。

动态表刷新超时由 STATEMENT_TIMEOUT_IN_SECONDS 参数确定,定义账户或仓库在自动取消前的持续时间上限。

以下各部分更详细地解释了动态表刷新:

动态表刷新模式

动态表刷新过程以两种方式之一进行:

  1. 增量刷新: 此自动化过程分析动态表的查询,并计算自上次刷新以来的变更。然后它将这些变更合并到表中。有关支持的查询的详细信息,请参阅 增量刷新中支持的查询

  2. 完全刷新: 当自动化过程无法执行增量刷新时,它会执行完全刷新。这涉及对动态表执行查询,并完全替换以前的具体化结果。

查询中使用的构造决定是否可以使用增量刷新。创建动态表后,可以 监控表,以确定是使用增量刷新还是完全刷新来更新该表。

了解目标滞后

动态表刷新是根据数据的过时程度触发的,这种过时程度通常称为 目标滞后。当为动态表设置目标滞后时,此滞后是相对于图表根中的基表来衡量的,而不是直接上游的动态表。因此,请考虑将 链中的每个动态表 刷新到根所需的时间。否则,系统可能会跳过一些刷新,从而导致更高的实际滞后。

要查看连接到动态表的表图形,请参阅 使用 Snowsight 检查动态表的图

目标滞后通过以下方式之一指定:

  1. 新鲜度度量:定义动态表内容滞后于基表更新的最长时间。

    以下示例将 product 动态表设置为每小时刷新并保持新鲜度:

    ALTER DYNAMIC TABLE product SET TARGET_LAG = '1 hour';
    
    Copy
  2. 下游:指定当依赖于该动态表的其他动态表需要刷新时,应按需刷新该动态表。更新内容从上游数据库对象推断而来。下游动态表仅在上游使用者需要时才更新。

    在下面的示例中,product 基于其他动态表,并设置为基于其下游动态表的目标滞后进行刷新:

    ALTER DYNAMIC TABLE product SET TARGET_LAG = DOWNSTREAM;
    
    Copy

目标滞后与动态表的刷新频率成反比:频繁刷新意味着较低的滞后。

考虑以下示例,其中动态表 2 (DT2) 根据动态表 1 (DT1) 定义。DT2 必须读取 DT1 来具体化其内容。此外,报告会通过查询来使用 DT2 数据。

两个动态表的简单示例,DT2 是基于 DT1 定义的。

可能出现以下结果,具体取决于每个动态表指定其滞后的方式:

动态表 1 (DT1)

动态表 2 (DT2)

刷新结果

TARGET_LAG = DOWNSTREAM

TARGET_LAG = 10minutes

DT2 最多每 10 分钟更新一次。DT1 从 DT2 推断其滞后,并在每次 DT2 需要更新时都会更新。

TARGET_LAG = 10minutes

TARGET_LAG = DOWNSTREAM

应避免这种情况。报告查询不会收到任何数据。DT 1 经常刷新,DT2 不会刷新,因为没有基于 DT2 的动态表。

TARGET_LAG = 5minutes

TARGET_LAG = 10minutes

DT2 大约每 10 分钟使用 DT1 的数据更新一次,而后者最多 5 分钟更新一次。

TARGET_LAG = DOWNSTREAM

TARGET_LAG = DOWNSTREAM

DT2 不会定期刷新,因为 DT1 并无具有明确滞后的下游子表。

增量刷新中支持的查询

下表描述了当前支持增量刷新的表达式、关键字和子句。有关不支持增量刷新的查询列表,请参阅 对增量刷新支持的限制

关键字/子句

对增量刷新的支持

WITH

公用表表达式 (CTE),在子查询中使用支持增量刷新的功能。

SELECT 中的表达式

包括使用确定性内置函数和 不可变 用户定义函数 的表达式。

FROM

源表、视图和其他动态表。不支持 FROM 子句(例如,WHERE EXISTS)外部的子查询。

OVER

全部:doc:窗口函数</user-guide/functions-window-using>

WHERE/HAVING/QUALIFY

具有在 SELECT 中有效的相同表达式的筛选器。

JOIN(以及用于联接表的其他表达式)

支持增量刷新的联接类型包括内部联接、外部联接和交叉联接。您可以在联接中指定任意数量的表,联接中所有表的更新都会反映在查询结果中。

UNION ALL

动态表支持 UNION ALL。

GROUP BY

动态表支持 GROUP BY。

重要

如果查询使用增量刷新不支持的表达式,则自动刷新过程将改用完全刷新,这可能会导致额外的开销。要确定使用哪种刷新模式,请参阅 确定使用增量刷新还是完全刷新

当使用增量刷新的动态表使用 IMMUTABLE 用户定义的函数 (UDF) 时,替换该函数会导致该表中出现未定义的行为。增量刷新不支持 VOLATILE UDFs。

运算符如何增量刷新

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

运算符

增量

注意事项

SELECT <scalar expressions>

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

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

WHERE <scalar expressions>

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

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

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

FROM <base table>

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

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

建议:

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

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

<query> UNION ALL <query>

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

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

WITH <CTE list> <query>

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

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

标量汇总

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

如果动态表包含标量汇总,只有当该汇总从不经常变更的表中读取,并且查询的其余部分实现良好递增时,才将其设置为增量刷新模式。

例如,假设 important_attrs 很少变更,则以下查询是增量刷新的理想候选项:

SELECT * FROM product WHERE attr IN
  (SELECT attr FROM important_attrs)
Copy

GROUP BY <keys>

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

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

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 联接,位置非常重要。

完全刷新中支持的非确定性函数

动态表支持以下非确定性函数。请注意,这些函数仅支持完全刷新。有关增量刷新不支持的列表,请参阅 对增量刷新支持的限制

当动态表依赖于其他动态表时数据如何刷新

如果将动态表滞后指定为时间度量,自动刷新过程会根据动态表的目标滞后时间确定刷新时间表。该过程会选择一个最符合表目标滞后时间的时间表。

备注

目标滞后不是保证,而是 Snowflake 尝试达到的目标。动态表中的数据会在尽可能不超出目标滞后的时间进行刷新。但是,由于仓库大小、数据大小、查询复杂性和类似因素等缘故,可能会超出目标滞后。

为了在 一个动态表依赖于另一个动态表 的情况下保持数据一致,该过程会在合适的时间刷新账户中的所有动态表。不太频繁的刷新在时间上与较为频繁的刷新相吻合。

例如,假设动态表 A 的目标滞后为两分钟,并且查询目标滞后为一分钟的动态表 B。该过程可能会确定 A 应每 96 秒刷新一次,而 B 应每 48 秒刷新一次。因此,该过程可能会采用以下时间表:

具体时间点

刷新的动态表

2022-12-01 00:00:00

A、B

2022-12-01 00:00:48

B

2022-12-01 00:01:36

A、B

2022-12-01 00:02:24

B

这意味着在任何给定时间,当您查询一组相互依赖的动态表时,查询的是这些表中数据的相同“快照”。

请注意,动态表的目标滞后不能短于其所依赖的动态表的目标滞后。例如,假设:

  • 动态表 A 查询动态表 B 和 C。

  • 动态表 B 的目标滞后为五分钟。

  • 动态表 C 的目标滞后为一分钟。

这意味着 A 的目标滞后时间不得短于五分钟(即,不得短于 B 和 C 的滞后时间中较长的一个)。

如果将 A 的滞后设置为五分钟,该过程将设置具有以下目标的刷新时间表:

  • 经常刷新 C,使其滞后短于一分钟。

  • 经常同时刷新 A 和 B,使它们的滞后短于五分钟。

  • 确保 A 和 B 的刷新在时间上与 C 的刷新相吻合,以确保快照隔离。

注意:如果刷新用时过长,排程器可能会跳过刷新以尝试保持最新状态。但是,快照隔离会被保留。

语言: 中文