dbt v1.9.8中check策略check_cols: all新增列时快照失败(回归问题)
dbt快照check策略+check_cols: all时新增源表列执行失败的临时解决方案
问题背景
使用check快照策略并设置check_cols: all时,给源模型新增列会导致dbt snapshot执行失败,抛出invalid identifier 'SNAPSHOTTED_DATA.NEW_COLUMN_NAME'错误。dbt会在新列被添加到快照表之前尝试从现有快照表中查询该列,直接中断构建。这是已修复问题#3146的回归,目前已提交新bug报告#11735。
临时解决办法
除了手动执行ALTER TABLE新增列或临时切换快照策略外,还有以下可行方案:
1. 临时指定明确的check_cols列表
将当前快照表已存在的列明确列在check_cols中,跳过新列,执行一次快照后再改回check_cols: all:
snapshots: - name: my_snapshot config: unique_key: id strategy: check check_cols: [id, name, age] # 仅包含快照表已有的列
执行dbt snapshot成功完成后,再将配置改回check_cols: all,后续快照即可正常处理schema变更。
2. 自定义宏处理列引用
通过覆盖dbt的快照宏,在生成对比SQL时对缺失的列做兼容处理。以Snowflake为例,修改snapshot_check_strategy相关宏,在引用快照表列时自动适配缺失列:
{% macro snapshot_check_strategy(node, snapshotted_rel, current_rel, config, target_exists) %} {% set check_cols = config.get('check_cols') %} {% if check_cols == 'all' %} {% set check_cols = current_rel.columns | map(attribute='name') | list %} {% endif %} {% set snapshotted_col_names = snapshotted_rel.columns | map(attribute='name') | list %} {% set comparison_pairs = [] %} {% for col in check_cols %} {% if col in snapshotted_col_names %} {% do comparison_pairs.append( (col, snapshotted_rel ~ "." ~ col, current_rel ~ "." ~ col) ) %} {% else %} {% do comparison_pairs.append( (col, "NULL AS " ~ col, current_rel ~ "." ~ col) ) %} {% endif %} {% endfor %} # 后续对比逻辑使用处理后的comparison_pairs生成SQL {% endmacro %}
将上述宏放在项目的macros目录下,dbt执行时会优先使用自定义宏,避免查询不存在的列报错。
3. 预钩子自动同步schema
编写自定义宏,在快照执行前自动对比源表与快照表的列,新增缺失的列:
{% macro sync_snapshot_columns(snapshot_name, source_model) %} {% set source_cols = adapter.get_columns_in_relation(ref(source_model)) %} {% set snapshot_cols = adapter.get_columns_in_relation(ref(snapshot_name)) %} {% set source_col_names = source_cols | map(attribute='name') | list %} {% set snapshot_col_names = snapshot_cols | map(attribute='name') | list %} {% set missing_cols = source_col_names | reject('in', snapshot_col_names) | list %} {% for col in missing_cols %} {% set col_def = source_cols | selectattr('name', 'equalto', col) | first %} {% set alter_stmt = "ALTER TABLE " ~ ref(snapshot_name) ~ " ADD COLUMN " ~ col ~ " " ~ col_def.data_type %} {% do run_query(alter_stmt) %} {% endfor %} {% endmacro %}
然后在快照配置中添加预钩子:
snapshots: - name: my_snapshot config: unique_key: id strategy: check check_cols: all pre-hook: "{{ sync_snapshot_columns('my_snapshot', 'your_source_model_name') }}"
这样每次执行快照前会自动同步缺失的列,无需手动操作。
补充说明
- 该问题仅在dbt-core 1.9.x版本出现,建议关注官方issue的修复进度;
- 若团队频繁进行schema变更,预钩子同步的方案可以长期使用,减少手动操作成本。
内容的提问来源于stack exchange,提问作者omar
相关产品推荐
相关产品推荐

