了解动态表刷新¶
动态表内容基于特定查询的结果。当动态表所基于的基础数据发生变更时,该表将会更新以反映这些变更。这些更新称为 刷新。此过程是自动化的,并且涉及到分析表的基础查询。
动态表刷新超时由 STATEMENT_TIMEOUT_IN_SECONDS 参数确定,定义账户或仓库在自动取消前的持续时间上限。
以下各部分更详细地解释了动态表刷新:
动态表刷新模式¶
动态表刷新过程以两种方式之一进行:
增量刷新: 此自动化过程分析动态表的查询,并计算自上次刷新以来的变更。然后它将这些变更合并到表中。有关支持的查询的详细信息,请参阅 增量刷新中支持的查询。
完全刷新: 当自动化过程无法执行增量刷新时,它会执行完全刷新。这涉及对动态表执行查询,并完全替换以前的具体化结果。
查询中使用的构造决定是否可以使用增量刷新。创建动态表后,可以 监控表,以确定是使用增量刷新还是完全刷新来更新该表。
了解目标滞后¶
动态表刷新是根据数据的过时程度触发的,这种过时程度通常称为 目标滞后。当为动态表设置目标滞后时,此滞后是相对于图表根中的基表来衡量的,而不是直接上游的动态表。因此,请考虑将 链中的每个动态表 刷新到根所需的时间。否则,系统可能会跳过一些刷新,从而导致更高的实际滞后。
要查看连接到动态表的表图形,请参阅 使用 Snowsight 检查动态表的图。
目标滞后通过以下方式之一指定:
新鲜度度量:定义动态表内容滞后于基表更新的最长时间。
以下示例将
product
动态表设置为每小时刷新并保持新鲜度:ALTER DYNAMIC TABLE product SET TARGET_LAG = '1 hour';下游:指定当依赖于该动态表的其他动态表需要刷新时,应按需刷新该动态表。更新内容从上游数据库对象推断而来。下游动态表仅在上游使用者需要时才更新。
在下面的示例中,
product
基于其他动态表,并设置为基于其下游动态表的目标滞后进行刷新:ALTER DYNAMIC TABLE product SET TARGET_LAG = DOWNSTREAM;
目标滞后与动态表的刷新频率成反比:频繁刷新意味着较低的滞后。
考虑以下示例,其中动态表 2 (DT2) 根据动态表 1 (DT1) 定义。DT2 必须读取 DT1 来具体化其内容。此外,报告会通过查询来使用 DT2 数据。
可能出现以下结果,具体取决于每个动态表指定其滞后的方式:
动态表 1 (DT1) |
动态表 2 (DT2) |
刷新结果 |
---|---|---|
|
|
DT2 最多每 10 分钟更新一次。DT1 从 DT2 推断其滞后,并在每次 DT2 需要更新时都会更新。 |
|
|
应避免这种情况。报告查询不会收到任何数据。DT 1 经常刷新,DT2 不会刷新,因为没有基于 DT2 的动态表。 |
|
|
DT2 大约每 10 分钟使用 DT1 的数据更新一次,而后者最多 5 分钟更新一次。 |
|
|
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> |
通过扫描上次刷新以后添加到表或从表中移除的微分区来实现递增。 |
成本随添加或移除的微分区中的数据量线性增长。 建议:
|
<query> UNION ALL <query> |
通过取两边更改并集实现递增。 |
表现良好,没有需要注意的特殊事项。 |
WITH <CTE list> <query> |
通过计算每个常用表表达式的更改实现递增。 |
WITH 使复杂查询更容易读取。注意不要使单个动态表的定义过于复杂。有关更多信息,请参阅 将动态表的管道链接在一起 和 优化复杂动态表的增量刷新模式性能。 |
标量汇总 |
标量汇总目前没有实现有效递增。当其输入发生变化时,会完全重新计算。 |
如果动态表包含标量汇总,只有当该汇总从不经常变更的表中读取,并且查询的其余部分实现良好递增时,才将其设置为增量刷新模式。 例如,假设 SELECT * FROM product WHERE attr IN
(SELECT attr FROM important_attrs)
|
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,以此实现递增。然后递增此分解查询。 内部联接递增如下所示。通过检查在一端的变更键是否在另一端已经存在,来实现不存在值的递增。 |
建议:
|
完全刷新中支持的非确定性函数¶
动态表支持以下非确定性函数。请注意,这些函数仅支持完全刷新。有关增量刷新不支持的列表,请参阅 对增量刷新支持的限制。
当动态表依赖于其他动态表时数据如何刷新¶
如果将动态表滞后指定为时间度量,自动刷新过程会根据动态表的目标滞后时间确定刷新时间表。该过程会选择一个最符合表目标滞后时间的时间表。
备注
目标滞后不是保证,而是 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 的刷新相吻合,以确保快照隔离。
注意:如果刷新用时过长,排程器可能会跳过刷新以尝试保持最新状态。但是,快照隔离会被保留。