创建动态表

本主题概述了创建动态表的关键概念。

开始之前,请确保您 有权创建动态表,并且动态表查询使用的所有对象都启用了 更改跟踪

创建动态表时可能会有一些限制。有关完整列表,请参阅 动态表限制

启用更改跟踪

在创建具有增量刷新模式的动态表时,如果尚未对其查询的表启用更改跟踪,Snowflake 会自动尝试对其启用更改跟踪。为支持增量刷新,必须对动态表使用的所有基础对象启用 非零 Time Travel 保留 的更改跟踪。

随着基础对象的变化,动态表也会发生变化。如果您重新创建一个基础对象,您必须重新启用更改跟踪。

备注

Snowflake 不会自动尝试在使用完全刷新模式创建的动态表上启用更改跟踪。

要对特定数据库对象启用更改跟踪,请在该对象上使用 ALTER TABLEALTER VIEW 和类似命令。创建动态表的用户必须具有 OWNERSHIP 权限,才能对所有基础对象启用更改跟踪。

要检查是否启用了更改跟踪,请在基础对象上使用 SHOW VIEWSSHOW TABLES 和类似命令,并检查 change_tracking 列。

支持的基础对象

动态表支持以下基础对象:

  • Snowflake 管理的 Apache Iceberg™ 表

  • 外部管理的 Apache Iceberg™ 表

示例:创建简单的动态表

假设您要创建一个动态表,该表包含来自名称为 staging_table 的表的 product_idproduct_name 列,并且您决定:

  • 您希望动态表中的数据最多比 staging_table 中的数据滞后 20 分钟。

  • 您希望将仓库 mywh 用于 刷新 所需的计算资源。

  • 您希望自动选择刷新模式。

  • 您希望动态表在创建时同步刷新。

  • 您希望自动选择刷新模式,并希望动态表在创建时同步刷新。

要创建此动态表,请执行以下 CREATE DYNAMIC TABLE SQL 语句:

CREATE OR REPLACE DYNAMIC TABLE my_dynamic_table
  TARGET_LAG = '20 minutes'
  WAREHOUSE = mywh
  REFRESH_MODE = auto
  INITIALIZE = on_create
  AS
    SELECT product_id, product_name FROM staging_table;
Copy

有关参数和变体语法的完整列表,请参阅 CREATE DYNAMIC TABLE 参考。

从 Snowflake 管理或外部管理的 Apache Iceberg™ 表创建动态表

从 Iceberg 表创建动态表与从普通表创建类似。可以像为普通表创建动态表一样,执行 CREATE DYNAMIC TABLE SQL 语句,将 Snowflake 管理的表或外部目录管理的表作为基础对象。

如果动态表以 Snowflake 管理的 Iceberg 表作为基表,则在以下情况下非常有用:希望您的数据管道操作基于 Snowflake 管理的 Iceberg 表中的数据,或者希望管道操作由其他引擎写入的 Iceberg 表。需要注意的是,外部引擎无法写入 Snowflake 管理的 Iceberg 表;对于 Snowflake 来说,它们是可读写的,而对于外部引擎则是只读的。

如果动态表以 外部(非 Snowflake)目录 管理的 Iceberg 表为基础(例如 AWS 管理、由 Apache Spark 等引擎写入),则适用于处理外部数据湖中的数据。您可以在外部管理的数据之上创建动态表,并在 Snowflake 中持续处理数据,而无需复制或导入数据。

使用 Iceberg 表的限制和注意事项

常规动态表动态 Iceberg 表 的所有限制仍然适用。

此外:

  • Iceberg 基表的所有限制均适用。有关更多信息,请参阅 注意事项和限制

  • 您可以创建动态表,读取 Snowflake 原生表、Snowflake 管理的 Iceberg 表以及外部管理的 Iceberg 表。

  • 对于外部管理的 Iceberg 基表,动态表以文件级别跟踪变化,而其他基表以行级别跟踪变化。在外部管理的 Iceberg 表上频繁执行写入复制操作(例如更新或删除)可能会影响增量刷新性能。

使用回填创建动态表

Backfilling is a zero-copy, low-cost operation that makes source data immediately available in a dynamic table. You can create a dynamic table with initial data backfilled from a table or dynamic table, while you still define a custom refresh query for future updates.

With immutability constraints, only the immutable region is backfilled and remains unchanged even if the immutable region no longer matches the source. The mutable region is computed from the dynamic table's definition and base tables as usual.

Only data defined by the IMMUTABLE WHERE immutability constraint can be backfilled because the backfill data must remain unchanged, even if it differs from the upstream source.

回填使用示例

以下示例展示了如何从回填数据的表中创建新的动态表。

每个列名必须在回填表中存在,并且数据类型兼容,顺序必须与回填表相同。回填表的表属性和权限不会复制。

如果指定了 Time Travel 参数 AT | BEFORE,则会在指定时间从回填表中复制数据。

示例:从表的一部分回填

以下示例将 my_dynamic_table 的不可变区域从 my_backfill_table 回填,而可变区域则从动态表的定义计算得出。

在此场景下,如果动态表以增量刷新模式创建,重新初始化会删除所有可变行,仅重新填充可变区域。如果动态表以完全刷新模式创建,则会触发完全刷新,效果相同。

CREATE DYNAMIC TABLE my_dynamic_table (day TIMESTAMP, totalSales NUMBER)
  IMMUTABLE WHERE (day < '2025-01-01')
  BACKFILL FROM my_backfill_table
  TARGET_LAG = '20 minutes'
  WAREHOUSE = 'mywh'
  AS SELECT DATE_TRUNC('day', ts) AS day, sum(price)
    FROM my_base_table
    GROUP BY day;
Copy

示例:使用回填在动态表中恢复或修改数据

您无法直接编辑动态表的数据或定义。要恢复或修复数据,请按照以下替代步骤操作:

  1. 将动态表克隆为一个常规表。

  2. 根据需要修改克隆表。

  3. 从已编辑的表回填到新的动态表。

在以下示例中,my_dynamic_table 从销售基表 sales 汇总每日销售数据:

CREATE OR REPLACE TABLE sales(item_id INT, ts TIMESTAMP, sales_price FLOAT);

INSERT INTO sales VALUES (1, '2025-05-01 01:00:00', 10.0), (1, '2025-05-01 02:00:00', 15.0), (1, '2025-05-01 03:00:00', 11.0);
INSERT INTO sales VALUES (1, '2025-05-02 00:00:00', 11.0), (1, '2025-05-02 05:00:00', 13.0);


CREATE DYNAMIC TABLE my_dynamic_table
  TARGET_LAG = 'DOWNSTREAM'
  WAREHOUSE = mywh
  INITIALIZE = on_create
  IMMUTABLE WHERE (day <= '2025-05-01')
  AS
    SELECT item_id, date_trunc('DAY', ts) day, count(sales_price) AS sales_count FROM sales
    GROUP BY item_id, day;

SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dynamic_table;
Copy
+---------+------------+-------------+
| ITEM_ID | DAY        | SALES_COUNT |
|---------+------------+-------------|
| 1       | 2025-05-01 | 3           |
| 1       | 2025-05-02 | 2           |
+---------+------------+-------------+

您还可以选择将旧数据归档,以节省存储成本:

DELETE FROM sales WHERE ts < '2025-05-02';

ALTER DYNAMIC TABLE my_dynamic_table REFRESH;

SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dynamic_table;
Copy

之后,您发现 2025-05-01 的销售数据存在错误,其中 sales_count 应为 2。要修正该问题,请执行以下操作:

  1. my_dynamic_table 克隆为常规表:

    CREATE OR REPLACE TABLE my_dt_clone_table CLONE my_dynamic_table;
    
    Copy
  2. 更新克隆的表:

    UPDATE my_dt_clone_table SET
      sales_count = 2
      WHERE day = '2025-05-01';
    
    SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dt_clone_table;
    
    Copy
    +---------+------------+-------------+
    | ITEM_ID | DAY        | SALES_COUNT |
    |---------+------------+-------------|
    | 1       | 2025-05-01 | 2           |
    | 1       | 2025-05-02 | 2           |
    +---------+------------+-------------+
    
  3. 使用已编辑的克隆表作为回填源,重新创建该动态表。

    CREATE OR REPLACE DYNAMIC TABLE my_dynamic_table
      BACKFILL FROM my_dt_clone_table
      IMMUTABLE WHERE (day <= '2025-05-01')
      TARGET_LAG = 'DOWNSTREAM'
      WAREHOUSE = mywh
      INITIALIZE = on_create
      AS
        SELECT item_id, date_trunc('DAY', ts) day, count(sales_price) AS sales_count FROM sales
        GROUP BY item_id, day;
    
    Copy

    利用这种方法,您无需修改基表即可在动态表中恢复或更正数据:

    SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dynamic_table;
    
    Copy
    +---------+------------+-------------+
    | ITEM_ID | DAY        | SALES_COUNT |
    |---------+------------+-------------|
    | 1       | 2025-05-01 | 2           |
    | 1       | 2025-05-02 | 2           |
    +---------+------------+-------------+
    

示例:使用回填修改动态表的架构

您无法直接更改动态表的架构。要更新架构(例如,添加一列),请按照以下步骤操作:

  1. 将动态表克隆为一个常规表。以下示例使用基于 sales 创建的 my_dynamic_table`(见 :ref:`上文 <label-data-surgery-example>)。

    CREATE OR REPLACE TABLE my_dt_clone_table CLONE my_dynamic_table;
    
    Copy
  2. 修改克隆表的架构:

    ALTER TABLE my_dt_clone_table ADD COLUMN sales_avg FLOAT;
    
    SELECT item_id, to_char(day, 'YYYY-MM-DD') as DAY, SALES_COUNT, SALES_AVG FROM my_dt_clone_table;
    
    Copy
  3. (可选)向新列填充数据。

  4. 使用已编辑的克隆表作为回填源,重新创建该动态表。

    CREATE OR REPLACE DYNAMIC TABLE my_dynamic_table
      BACKFILL FROM my_dt_clone_table
      IMMUTABLE WHERE (day <= '2025-05-01')
      TARGET_LAG = 'DOWNSTREAM'
      WAREHOUSE = mywh
      INITIALIZE = on_create
      AS
        SELECT item_id, date_trunc('DAY', ts) day, count(sales_price) AS sales_count, avg(sales_price) as sales_avg FROM sales
        GROUP BY item_id, day;
    
    Copy

    利用这种方法,您无需修改基表即可在动态表中恢复或更正数据:

    SELECT item_id, to_char(day, 'YYYY-MM-DD') as DAY, SALES_COUNT, SALES_AVG, metadata$is_immutable as IMMUTABLE from my_dynamic_table ORDER BY ITEM_ID, DAY;
    
    Copy
    +---------+------------+-------------+-----------+-----------+
    | ITEM_ID | DAY        | SALES_COUNT | SALES_AVG | IMMUTABLE |
    |---------+------------+-------------|-----------|-----------|
    | 1       | 2025-05-01 | 3           | NULL      | TRUE      |
    | 1       | 2025-05-02 | 2           | 12        | FALSE     |
    +---------+-------------+------------+-----------+-----------+
    

Limitations and considerations when you create a dynamic table with backfilled data

常规动态表的所有限制 以及 不可变性约束的限制 仍然适用。

The following additional limitations and considerations apply:

  • Currently, only regular and dynamic tables can be used for backfilling.

  • 在新建动态表时,您不能指定策略或标签,因为它们会从回填表中复制。

  • 新建动态表与回填表的群集密钥必须相同。

创建动态表的最佳实践

将动态表的管道链接在一起

定义新的动态表时,不要定义包含许多嵌套语句的大型动态表,而应使用小型动态表与管道组合的方式。

您可以设置动态表来查询其他动态表。例如,想象这样一个场景:您的数据管道从暂存表中提取数据以更新各种维度表(例如,customerproductdatetime)。此外,管道还根据这些维度表中的信息更新汇总 sales 表。通过将维度表配置为查询暂存表,将汇总 sales 表配置为查询维度表,可以创建类似于任务图的级联效果。

在此设置中,仅在维度表刷新成功完成后才能执行汇总 sales 表的刷新。这样可以确保数据的一致性并达到滞后目标。通过自动刷新过程,源表中的任何更改都会在适当的时候触发对所有从属表的刷新。

任务图和动态表 DAGs 的比较

对复杂任务图使用“控制器”动态表

如果您有一个动态表的复杂图表,其中包含许多根节点和叶节点,并且您想使用单个命令对整个任务图执行操作(例如更改滞后、手动刷新、挂起),请执行以下步骤:

  1. 将所有动态表的 TARGET_LAG 值设置为 DOWNSTREAM

  2. 创建一个“控制器”动态表,从任务图中的所有叶中读取。要确保此控制器不消耗资源,请执行以下语句:

    CREATE DYNAMIC TABLE controller
      TARGET_LAG = <target_lag>
      WAREHOUSE = <warehouse>
      AS
        SELECT 1 A FROM <leaf1>, …, <leafN> LIMIT 0;
    
    Copy
  3. 使用此控制器控制整个图表。例如:

  • 为任务图设置新的目标滞后。

    ALTER DYNAMIC TABLE controller SET
      TARGET_LAG = <new_target_lag>;
    
    Copy
  • 手动刷新任务图。

    ALTER DYNAMIC TABLE controller REFRESH;
    
    Copy

使用瞬态动态表降低存储成本

瞬态 动态表可随着时间的推移可靠地维护数据,并支持数据保留期内的 Time Travel,但不保留超过故障安全期的数据。默认情况下,动态表数据在 故障安全 存储中保留七天。

对于具有高刷新吞吐量的动态表,这会显著增加存储消耗。因此,只有当动态表的数据不需要与永久表提供的数据保护和恢复处于相同级别时,才应将其变为瞬态表。

您可以使用 CREATE DYNAMIC TABLE 语句创建瞬态动态表,或将现有动态表克隆到瞬态动态表。

动态表创建故障排除

创建动态表时,初始刷新要么按计划 (ON_SCHEDULE) 进行,要么在创建时立即进行 (ON_CREATE)。初始数据填充或 初始化 取决于此初始刷新发生的时间。例如,对于 ON_CREATE,如果初始化触发上游动态表刷新,则可能需要更长时间。

初始化可能需要一些时间,具体取决于扫描的数据量。要查看进度,请执行以下操作:

  1. 登录 Snowsight

  2. In the navigation menu, select Monitoring » Query History.

  3. Filters 下拉列表中,在 SQL Text 筛选器中输入 CREATE DYNAMIC TABLE,并在 Warehouse 筛选器中输入您的仓库名称。

  4. 选择 SQL text 下动态表的查询,并使用 Query DetailsQuery Profile 选项卡跟踪进度。

语言: 中文