动态表刷新边界

使用动态表刷新边界来解耦动态表管道,同时仍然读取上游结果。

当一个动态表引用另一个动态表时,两者将作为单个管道一起刷新。虽然这适用于大多数场景,但在某些用例中,例如跨团队边界共享数据,数据刷新需求可能会有所不同。您可以通过将上游引用封装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中,将这两个动态表声明为彼此独立(因此属于不同的管道)。快照隔离仅在单个管道内得到保证,因此跨刷新边界的动态表不提供彼此的快照隔离。

概述

默认情况下,当动态表从另一个动态表读取时,Snowflake 会执行以下操作:

  • 将两个表作为单个管道的一部分一起刷新。

  • 坐标刷新,以便下游动态表能够看到管道中所有上游动态表的 快照隔离

  • 强制执行管道级规则,例如目标滞后检查。

在某些管道中,您不希望每个关系都导致两个动态表一起刷新。常见示例包括:

  • 跨团队管道,其中一个团队发布另一个团队使用的动态表,但下游动态表不应影响或继承上游管道。

  • 增量迁移,您将上游管道步骤转换为动态表,但不希望下游使用者开始与之协调刷新。

  • Dynamic-table-on-view-on-dynamic-table 模式,其中动态表从查询另一个动态表的视图中读取。不支持此模式,除非视图包装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中。

刷新边界使这种分离变得明确:边界内的输入被视为属于单独的管道,并且像常规表一样读取。

语法

DYNAMIC_TABLE_REFRESH_BOUNDARY( <object_name> )

其中:

object_name

表、视图、动态表或公用表表达式 (CTE) 名称。

在动态表定义的 FROM / JOIN 子句中(包括在 CTEs 和 UNION 分支内)使用此关键字。

示例

以下示例从查询另一个动态表的视图中读取数据。如果没有刷新边界,则不支持创建从另一个动态表上的视图读取数据的动态表。将视图封装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中,使这种模式成为可能:

CREATE DYNAMIC TABLE analytics.click_analytics_dt
  WAREHOUSE = analytics_wh
  TARGET_LAG = '5 minutes'
AS
SELECT *
FROM DYNAMIC_TABLE_REFRESH_BOUNDARY(analytics.enriched_clicks_view);

以下示例将直接引用的动态表与上游动态表刷新计划较长的视图联接起来。将视图封装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中,防止下游动态表每 5 分钟触发一次高成本的上游刷新,同时仍允许其读取最新的可用版本。不保证跨刷新边界的快照隔离:

CREATE DYNAMIC TABLE data_eng.enriched_clicks_dt
  WAREHOUSE = de_wh
  TARGET_LAG = '5 minutes'
AS
SELECT
  c.*,
  p.product_name
FROM data_eng.clickstream_dt AS c
LEFT JOIN DYNAMIC_TABLE_REFRESH_BOUNDARY(product_db.active_products_view) AS p
  ON c.product_id = p.product_id;

行为

刷新边界如何更改依赖项

当您在动态表定义中将输入封装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中:

  • 该输入被视为此定义的刷新边界输入。

  • 此定义的管道中不包含可从该输入访问的任何动态表。

  • 刷新时,动态表会读取这些对象的当前版本,而不是跨管道协调的数据时间戳。

因此:

无跨边界级联刷新

刷新下游动态表不会触发只能通过刷新边界访问的动态表的刷新。

独立调度

下游动态表的目标滞后和刷新计划会忽略只能通过边界访问的动态表。

无跨边界快照隔离

下游动态表会读取刷新时可用的上游数据的任何版本。跨边界的数据不保证与适用于其他上游依赖项的 快照隔离 保持一致。

快照隔离与刷新边界

在单个管道(无边界)内,Snowflake 能保证所有参与该管道的上游动态表之间实现 快照隔离

刷新边界故意削弱了对跨边界的依赖项的这种保证:

  • 在边界内: 对象根据自己的管道刷新和协调。

  • 在边界之外: 下游动态表会读取刷新时可用的任何版本。

因此,单个动态表定义可以引用两种类型的输入:

  • 对上游动态表的 直接引用,这些表参与管道内的快照隔离和协调刷新。

  • 刷新边界引用,独立读取上游数据的最新可用版本,无需快照隔离。

仅对上游和下游动态表之间不需要快照隔离的依赖项使用刷新边界。

用例

解耦跨团队管道

不同的团队可能拥有不同的逻辑管道部分:

  • 团队 A: 发布一个在整个组织中使用的核心动态表。

  • 团队 B: 定义一个下游动态表,将核心动态表与特定于团队的数据联接起来。

团队 B 可以将团队 A 的输出封装在刷新边界内,以便:

  • 避免将团队 A 的动态表拉入他们自己的管道中。

  • 保持自己的刷新计划独立。

  • 将团队 A 的动态表视为定期更新的外部表。

在动态表的视图上启用动态表

如果没有刷新边界,则不支持创建从另一个动态表上的视图读取数据的动态表。通过刷新边界,您可以将视图依赖项显式标记为边界:

CREATE VIEW v_orders AS
SELECT *
FROM orders_dt;

CREATE DYNAMIC TABLE order_summary_dt
  WAREHOUSE = analytics_wh
  TARGET_LAG = '15 minutes'
AS
SELECT
  customer_id,
  COUNT(*) AS num_orders
FROM DYNAMIC_TABLE_REFRESH_BOUNDARY(v_orders)
GROUP BY customer_id;

此处,order_summary_dt

  • 通过刷新边界从 orders_dt 读取数据。

  • 不属于与 orders_dt 相同的管道。

  • 在刷新时读取当时可用的 orders_dt 的任意版本数据。

示例:团队拥有的边界视图

一种常见的模式是,一个团队同时拥有一个动态表和其上的视图,并在视图定义中应用刷新边界。然后,其他团队使用该视图,而不会向所属团队的动态表引入新的依赖项。

-- Team A: owns product_catalog_dt and publishes a boundary view
CREATE DYNAMIC TABLE product.product_catalog_dt
  WAREHOUSE = product_wh
  TARGET_LAG = '1 hour'
AS
SELECT *
FROM product.raw_products;

CREATE VIEW product.active_products_public_v AS
SELECT * FROM DYNAMIC_TABLE_REFRESH_BOUNDARY(product.product_catalog_dt)
WHERE is_active = TRUE;

-- Team B: consumes Team A's view in their own dynamic table
CREATE DYNAMIC TABLE analytics.active_product_clicks_dt
  WAREHOUSE = analytics_wh
  TARGET_LAG = '5 minutes'
AS
SELECT
  c.*,
  p.product_name
FROM analytics.clickstream_dt AS c
JOIN product.active_products_public_v AS p
  ON c.product_id = p.product_id;

在此模式中:

  • 团队 A 通过在 product.active_products_public_v 中将 product_catalog_dt 封装在刷新边界内,从而控制该刷新边界。

  • 团队 B 和其他团队定义自己的动态表,这些表仅引用已发布的视图。

  • 这些下游动态表不会将 product_catalog_dt 加入到它们自己的管道中;尽管可以通过视图看到其数据,product_catalog_dt 仍然保持在它们的管道之外。

增量迁移到动态表

如果将现有管道步骤迁移到动态表,您可能不希望下游使用者执行以下操作:

  • 开始触发新动态表的刷新。

  • 继承新的目标滞后要求。

将新的动态表(或其之上的视图)封装在刷新边界中,这样下游动态表就可以使用它,而无需将其添加到同一管道中。

目标滞后

刷新边界也会影响目标滞后的执行方式。

上游动态表的目标滞后必须等于或小于同一管道中任何下游动态表的目标滞后。通过 DYNAMIC_TABLE_REFRESH_BOUNDARY() 引用的动态表不属于同一个管道,因此此规则不适用于跨边界。

刷新边界内的上游动态表保留自己的目标滞后和调度行为;它们不会因跨界的下游选择而收紧或放松。

约束与限制

刷新边界受一些重要规则的约束:

不允许在刷新边界内部和外部使用相同的动态表

单个定义中对同一上游动态表的所有引用必须直接在定义中或封装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中。混合使用两者将允许在不同版本中读取相同的动态表。Snowflake 会阻止这些定义并返回描述性错误。

不支持的边界目标

DYNAMIC_TABLE_REFRESH_BOUNDARY() 必须封装命名对象(表、视图、动态表或 CTE)。它不能进行封装:

  • 内联子查询。

  • UDTFs 表函数。

  • 任意 TABLE(...) 调用。

动态表外部的影响

您可以在常规 SELECT 查询中调用 DYNAMIC_TABLE_REFRESH_BOUNDARY(),但在动态表定义之外,它是无操作的。

最佳实践

在动态表管道中使用刷新边界时:

在以下情况下使用刷新边界:

  • 您希望使用另一个团队的动态表,而不联接其管道。

  • 您不需要与特定上游依赖项进行快照隔离。

  • 动态表依赖于引用另一个动态表的视图。仅当视图或上游动态表封装在 DYNAMIC_TABLE_REFRESH_BOUNDARY() 中时,才支持这种模式。

在以下情况下避免刷新边界:

  • 您需要跨该依赖项进行快照隔离。

  • 您希望下游刷新与上游动态表协调,并在需要时进行级联刷新。

  • 您依赖于整个管道的全局目标滞后关系。