优化动态表性能¶
本主题介绍优化动态表性能的技术,分为设计变更和调整两类。
在优化动态表之前,您可能需要诊断刷新缓慢的原因。请参阅 诊断刷新缓慢问题 以获取分步工作流程。
有关性能类别的背景信息,请参阅 性能决策。
设计变更¶
设计变更需要重新创建动态表,但对性能的影响更大。
备注
我们建议您将变更分组并统一重新创建表,而不是进行增量修改。
选择刷新模式¶
您选择的刷新模式会对性能产生重大影响,因为它决定了 Snowflake 在每次刷新期间处理的数据量。有关每种模式的工作原理的信息,请参阅 动态表刷新模式。
重要
支持增量刷新的动态表不能是使用完全刷新的动态表的下游。
使用以下决策过程来选择刷新模式:
根据 支持的查询结构 列表审查查询。并非所有查询运算符都支持增量刷新。有关 受 支持的运算符,请参阅 优化增量刷新查询,了解它们如何影响性能。
估算变更量,即两次刷新之间发生变更的数据所占的百分比。例如,当数据变更量低于 5% 时,增量刷新效果最佳。
评估数据局部性。检查源表是否已按动态表查询中计划用于联接、GROUP BY 或 PARTITION BY 子句的键进行聚类。较差的局部性会降低增量刷新效率。要改进局部性,请参阅 提高数据局部性。
根据下表选择模式:
模式
何时使用
增量
查询使用支持的运算符,两次刷新之间的数据变更量不到 5%,并且源表具有良好的数据局部性。
备注
增量刷新仍然可以扫描源表,而不仅仅是已变更的行。例如,联接一侧的新行必须与另一个表中的所有行匹配。即使是少量的变更也可能引发大量工作。
全量
数据有很大比例的变更,查询使用不受支持的运算符,或者数据缺乏局部性。
自动
您正在进行原型设计或测试。避免在生产环境中使用 AUTO,因其行为可能随 Snowflake 版本变化而改变。
创建动态表时,请在 CREATE DYNAMIC TABLE 语句中使用
REFRESH_MODE = INCREMENTAL或REFRESH_MODE = FULL指定模式。
要查看动态表使用哪种刷新模式,请参阅 刷新模式。
优化查询和管道¶
动态表查询和管道的结构会直接影响刷新性能。请参考以下指南,以减少每次刷新期间的工作量。
简化单条查询
使用内部联接(而非外部联接)。在增量刷新中,内部联接的性能更好。验证源数据中的参照完整性,以避免外部联接。
避免不必要的操作。移除冗余的 DISTINCT 子句和未使用的列。排除不常查询的宽列(例如大型 JSON 数据块)。
高效移除重复项。尽可能使用排名函数代替 DISTINCT。
有关特定 SQL 运算符如何影响增量刷新性能的详细指导,请参阅 优化增量刷新查询。
备注
有关完整示例,请参阅 教程:为 SCD Type 1 工作负载优化动态表性能。
将转换拆分到多个动态表
将复杂的转换分解到多个动态表,这样可以更轻松地识别瓶颈并改进调试。借助 不可变性约束,您还可以为不同的暂存区使用不同的刷新模式。
尽早添加筛选器。在最接近源数据的动态表中应用
WHERE子句,以减少下游表处理的行数。要避免下游表重复
DISTINCT操作,请在数据管道的前端移除重复行。减少每个表的操作次数。将联接、聚合或窗口函数移动到中间动态表中,而不是将它们全部组合在一个查询中。
先在中间表中将复合表达式(例如
DATE_TRUNC('minute', ts))物化,再按其分组。 是 优化聚合 Web 令牌 ()、 令牌或 编程访问令牌 。有关详细信息,请参阅 优化聚合。
备注
要找到最佳拆分点,需要反复试验。
考虑将基于不同键对数据进行混洗的操作(如 GROUP BY、DISTINCT、带 PARTITION BY 的窗口函数以及联接)进行拆分。这样每个动态表可以在其键操作上保持更好的数据局部性。有关特定于运算符的指南,请参阅 优化增量刷新查询。
以下示例演示如何将复杂查询拆分为中间动态表。
初始复杂查询:
CREATE DYNAMIC TABLE final_result AS
SELECT ...
FROM large_table a
JOIN dimension_table b ON ...
JOIN another_table c ON ...
GROUP BY ...;
通过添加中间动态表来拆分复杂管道:
CREATE DYNAMIC TABLE intermediate_joined AS
SELECT ...
FROM large_table a
JOIN dimension_table b ON ...;
CREATE DYNAMIC TABLE final_result AS
SELECT ...
FROM intermediate_joined
JOIN another_table c ON ...
GROUP BY ...;
有关运算符如何影响性能的详细信息和示例,请参阅 优化增量刷新查询。
将历史数据标记为不可变¶
使用 IMMUTABLE WHERE 子句告诉 Snowflake 某些行不会变更。这样可以缩小每次刷新期间的工作范围。
有关语法、示例和详细指南,请参阅 使用不可变性约束。
调整¶
调整不需要重新创建动态表。您可以在管道运行时进行调整。
调整仓库配置¶
您在 CREATE DYNAMIC TABLE 语句中指定的仓库会运行该表的所有刷新。仓库大小和配置直接影响刷新持续时间和成本。
有关仓库和动态表的更多信息,请参阅 了解动态表的仓库使用情况。有关一般仓库性能优化策略,请参阅 优化仓库以提高性能。
使用单独的仓库进行初始化¶
首次刷新需要处理的数据量通常远大于增量刷新。使用 INITIALIZATION_WAREHOUSE 在更大的仓库上运行初始化。为定期刷新预留更小、更具成本效益的仓库:
CREATE DYNAMIC TABLE my_dynamic_table
TARGET_LAG = 'DOWNSTREAM'
WAREHOUSE = 'XS_WAREHOUSE'
INITIALIZATION_WAREHOUSE = '4XL_WAREHOUSE'
AS <query>;
要为现有动态表添加或更改初始化仓库,请执行以下操作:
ALTER DYNAMIC TABLE my_dynamic_table SET INITIALIZATION_WAREHOUSE = '4XL_WAREHOUSE';
要移除初始化仓库并使用主仓库进行所有刷新,请执行以下操作:
ALTER DYNAMIC TABLE my_dynamic_table UNSET INITIALIZATION_WAREHOUSE;
要查看仓库配置,请使用 SHOW DYNAMIC TABLES 或者检查 DYNAMIC_TABLE_REFRESH_HISTORY 表函数。
需要时调整大小¶
为了在成本与性能之间取得平衡,应选择能够防止字节溢出且不超过工作负载并行使用能力的仓库大小。当更快的刷新至关重要时,请将大小稍微增加到超过成本最佳点。
动态表刷新的注意事项:
溢出的字节:当查询历史记录显示字节溢出到本地或远程存储时,仓库在刷新期间内存不足。较大的仓库可提供更多内存以防止溢出。查询太大而无法放入内存 是 Web 令牌 ()、 令牌或 编程访问令牌 。有关详细信息,请参阅 查询太大而无法放入内存。
初始刷新缓慢:当初始刷新速度较慢时,请考虑为初始创建设置 INITIALIZATION_WAREHOUSE,或临时调整仓库大小,然后在创建表后调小。
并行性饱和:超过某个点后,额外的并行性带来的收益会递减。在不将运行时间减半的情况下,将仓库大小增加一倍可能会使成本增加一倍。要检查刷新如何使用并行性,请查看 查询配置文件。
要调整仓库大小,请参阅 增加仓库规模。
有关成本注意事项,请参阅 虚拟仓库 Credit 使用量 和 使用仓库。
使用多集群仓库处理并发刷新¶
如果多个动态表共享一个仓库并频繁刷新队列,请考虑使用 多集群仓库。多集群仓库会在查询排队时自动添加集群,并在需求下降时自动移除集群。这样可以改善高峰期的刷新延迟,而无需在安静期为未使用的容量付费。
有关识别和减少队列的指南,请参阅 减少队列。
多集群仓库需要 Enterprise Edition 或更高版本。有关成本注意事项,请参阅 为多集群仓库设置扩展策略。
确定合适的目标滞后¶
目标滞后控制动态表的刷新频率。较短的目标滞后意味着数据更新更及时,但刷新更频繁,计算成本更高。有关目标滞后工作原理的更多信息,请参阅 了解动态表目标滞后。
使用以下建议来优化工作负载的目标滞后:
为无需独立保证数据新鲜度的中间表使用 DOWNSTREAM。这些表仅在下游表需要时才会刷新。
检查刷新历史记录以找到合适的滞后:使用 DYNAMIC_TABLE_REFRESH_HISTORY 或 Snowsight 分析刷新持续时间和跳过的刷新。将目标滞后设置为略高于典型刷新持续时间。
更改目标滞后¶
ALTER DYNAMIC TABLE my_dynamic_table SET TARGET_LAG = '1 hour';
要将动态表设置为根据下游需求刷新,请执行以下操作:
ALTER DYNAMIC TABLE my_dynamic_table SET TARGET_LAG = DOWNSTREAM;
提高数据局部性¶
局部性 描述 Snowflake 存储具有相同键值的行的紧密程度。当具有匹配键的行跨越较少的微分区(局部性较好)时,增量刷新扫描的数据较少。当匹配键跨越许多微分区(局部性较差)时,增量刷新可能比完全刷新需要更长的时间。
有关 Snowflake 如何存储数据的更多信息,请参阅 微分区和数据聚类。
聚类源表¶
提高局部性的最有效方法是根据动态表查询中使用的键(JOIN、GROUP BY 或 PARTITION BY 键)对源表进行聚类:
ALTER TABLE my_source_table CLUSTER BY (join_key_column);
当您联接多个列并且无法按所有列进行聚类时,请执行以下操作:
按选择性最强的键优先对较大的表进行聚类。
考虑为相同数据创建按不同键聚类的多个副本,以便在不同的动态表中使用。
影响局部性的因素¶
除源表聚类外,还有两个因素会影响局部性。这些因素取决于您的数据模式,并且更难直接更改:
新数据如何与分区键对齐:当新行仅影响表的一小部分时,增量刷新速度会更快。这取决于数据引入模式,而不是查询结构。
例如,按小时分组的时间序列数据具有良好的局部性,因为新行共享最近的时间戳。按列分组且值分布在整个表中的数据局部性较差。
变更如何与动态表聚类保持一致:当 Snowflake 对动态表执行更新或删除操作时,它必须找到受影响的行。当更改的行紧密存储时,速度会更快。
例如,当动态表按时间自然排序时,对最近行的更新操作表现出色。分散在整个表中的更新操作速度较慢。此因素取决于工作负载模式,包括哪些行会变更以及变更频率。
因这些因素导致局部性较差时,请考虑是否可以调整上游的数据模型或引入模式。