参考:dbt Incremental Strategies | Indicium Engineering (medium.com)
本文讨论dbt的增量策略,介绍工作原理、以及各自优缺点。下篇讲解如何在模型中实现增量策略。
使用增量模型可以仅仅处理最近的数据,减少数据处理成本和时间。当然首先要明确我们真的需要使用增量策略吗?增量物化选项是dbt中高级强大的特性,并不需要每个模型都需要使用。使用增量物化模型需要增加一些配置以及一堆jinja条件代码。
增量策略场景
前面我们提及无需在每个模型中使用策略策略。很多场景中完全刷新策略(full refresh)可能更好,本节简要讨论这个议题。在DW中,通常模型缺省采用完全刷新策略。如果没有定义增量物化选项,则每次运行会重建表。首先会删除目标表,然后用整个源表中已转换数据创建并填充新的目标表。
你可能觉得这不是最优的转换过程,因为需要花大量时间和处理能力创建整个表,但它也有其优势之处。
首先,完全刷新策略在复杂性和处理成本/时间之间存在明显的权衡。它复杂度低,无需担心更合增量规则和配置,且能确保目标表可以接收到所有已转换数据,当然也需要花更多时间和资源重建整个表。如果表数据量不是很大,假设少于100万或更少,转换性能不是问题,也不用担心成本和时间,则坚持采用完全刷新策略没有问题。
回到低复杂性及生产率角度来看,使用完全刷新策略可以更快地把目标表提供给最终用户,从而尽快产生价值。这样最终用户可以自由地验证转换并给出反馈,要求更改或优化。
除此之外,在生产环境中有转换后的表可以让分析工程师更精确地了解数据情况,如:数据更新的方式和频率,以及每次运行中处理的数据量。这些都是模型优化步骤中需要考虑的重要问题。在优化步骤中,评估策略以减少转换的成本、处理量或处理时间。这可以通过多种方式实现,例如删除不生成值的列或更改模型物化方式等。下面总结下完全刷新策略的关键点:
分类 | 内容 |
---|---|
优势 | 实现简单、更快产生价值、保证所有数据插入至目标表,不考虑数据库更新规则 |
劣势 | 处理成本高、处理时间多 |
场景 | 不担心成本和时间时(表数据量小、或转换规则简单),静态数据多于动态数据,历史数据更新频繁 |
如果你需要降低成本或加快转换速度,或者待处理表经常接收新数据,并且你对dbt比较熟悉,则应该尝试增量模型。
增量模型
增量物化选项目标是为减少处理时间与成本,仅转换并插入最近新增的数据。为了让Dbt知道那些是最新的数据,表中应该有以下类型的列:date, datetime, timestamp, 或 int64。增量模型使用源表中列和目标表过滤那些数据需要增量转换、插入、更新或删除。
特别需要说明的是,增量策略不会捕获对旧记录所做的修改。因此,一个好的做法是定期以完全刷新模式运行表以更新历史数据。
如果满足以下三个条件,模型表将以增量方式运行:
(1) 目标表已经存在于数据库中;
(2) dbt不是以完全刷新模式运行(没有使用------full-refresh 选项);
(3) 运行模型配置了materialized='incremental'
dbt提供了四种类型增量策略:
- append
- merge
- delete+insert
- insert_overwrite
策略的可用性取决于你配置的数据库适配器。dbt官方文档列出了常见适配器及其策略支持列表。
data platform adapter | append |
merge |
delete+insert |
insert_overwrite |
dbt-postgres | ✅ | ✅ | ✅ | |
dbt-redshift | ✅ | ✅ | ✅ | |
dbt-bigquery | ✅ | ✅ | ||
dbt-spark | ✅ | ✅ | ✅ | |
dbt-databricks | ✅ | ✅ | ✅ | |
dbt-snowflake | ✅ | ✅ | ✅ | |
dbt-trino | ✅ | ✅ | ✅ | |
dbt-fabric | ✅ | ✅ |
dbt-postgres支持下面几种物理策略:
append
(缺省没有定义unique_key)merge
delete+insert
(缺省当定义了unique_key
)
追加策略(Append)
追加策略非常简单,它只获取选中的记录并将它们插入目标表中。它不能更新或删除记录,只能插入。只有当重复记录对你来说不是问题时,您才能使用此策略。Append不担心重复,它不会检查记录是否已经存在于目标表中,它只会插入新增的记录,不考虑是否重复。
分类 | 内容 |
---|---|
优势 | 简单直接;无需扫描目标表、处理成本低;处理时间少; |
劣势 | 不更新、删除记录,仅仅插入;存在重复记录; |
场景 | 当你只是想插入新增记录,重复记录都不是问题; |
合并策略(Merge)
合并策略解决重复记录问题,如果你指定唯一键(支撑组合列)能处理重复键问题。如果基于唯一键检查,目标记录已经存在目标表中,合并策略将更新记录,所以不会有重复记录。如果目标记录不存在则直接插入记录。
为了检查两个表的唯一键,合并策略需要扫描整个目标表,同时查询源表的部分记录。执行全表扫描会有较大的性能成本。如果合并策略不指定唯一键,则变成追加操作。
为了提升合并策略的性能,减少性能成本,目标表可以设置索引,避免执行目报表全表扫描。
分类 | 内容 |
---|---|
优势 | 避免重复 、百万级以下数据量运行良好 |
劣势 | 处理成本高,需要全表扫描(可以使用聚集索引提升性能) |
场景 | 表数据量相对小,避免重复记录,希望实现增量,且重复记录需要更新 |
删除插入
删除插入策略与合并策略类似,但采用插入新记录代替更新记录。首先删除已经存在的记录、然后插入新记录和已存在的记录;因为删除目标表中已经存在的记录,所以也不存在重复记录。
删除插入策略同样也需要全表扫描目标表进行比较唯一键,然后删除已经存在的记录并插入增量记录。采用删除而不是更新,这通常和目标数据支持的存储引擎相关,尤其是基于分区表的情况,采用直接删除分区效率更好。
插入覆盖
最后要介绍的是插入覆盖策略。主要解决全表扫描问题,该方案需要与分区一同工作。
分区表把表按照一定规则分成多个段。插入覆盖支持的分区类型包括:date, datetime, timestamp, int64 ,粒度可以为hour, day, month 或 year。如果按照int64类型分区需要指定范围,基于对应列值形成分区,所有分区中的记录采用基于相同的粒度值。
插入覆盖策略删除从目标表中删除已选择的分区,然后插入新增已转换的数据分区。因为采用分区表,避免了全表扫描。这是与合并策略的差异,极大地减少了处理数据的数量。
除了使用分区,过程与删除插入策略非常类似,但删除插入策略使用两个独立语句,删除和插入语句。插入覆盖使用合并语句。另外,插入覆盖策略复杂度高,如果分区字段配置不当会造成数据重复。
分类 | 内容 |
---|---|
优势 | 低处理成本、低处理时间 |
劣势 | 高度复杂、配置不当可能造成数据重复 |
场景 | 数据量非常大,性能和处理数据已经造成问题 |
总结
现在你应该对何时使用增量和何时不使用增量有了更清晰的概念。此外,你知道每种策略是如何工作的,并且知道何时使用何种策略。在下一篇文章中,我将展示如何在实践中实现增量策略。期待您的真诚反馈,更多内容请阅读数据分析工程专栏。