Skip to content

Commit 53ade57

Browse files
committed
perf: reuse columns from process_schema_changes in incremental materialization
Incremental materialization previously discarded the return value of `process_schema_changes`, causing each strategy macro (`merge`, `append`, `delete+insert`) to issue a second `DESCRIBE TABLE EXTENDED` on the target relation even though `check_for_schema_changes` had just DESCRIBEd it. This change: - captures the columns returned by `process_schema_changes` in both V1 and V2 paths - falls back to a single `adapter.get_columns_in_relation(existing_relation)` when `on_schema_change == 'ignore'` - threads the result through `strategy_arg_dict['dest_columns']` - teaches `databricks__get_merge_sql`, `get_delete_insert_sql`, and `get_insert_into_sql` to honor a pre-supplied `dest_columns` and skip their own `DESCRIBE` when provided Net effect: one fewer `DESCRIBE TABLE EXTENDED … AS JSON` round-trip per incremental model, per run. Verified on a project with 9 incremental stg models (V1 path, `on_schema_change: 'fail'`): target DESCRIBE count drops from 2 to 1 per model across merge, append, and delete+insert strategies. Resolves #1411 Co-authored-by: Isaac
1 parent 86d26c9 commit 53ade57

3 files changed

Lines changed: 48 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## dbt-databricks 1.13.0 (TBD)
2+
3+
### Under the Hood
4+
5+
- Reuse the columns returned by `process_schema_changes` in the incremental materialization so the downstream strategy macros (`merge`, `append`, `delete+insert`) no longer re-issue `DESCRIBE TABLE EXTENDED` on the target. Saves one metadata round-trip per incremental model. Mirrors the existing `dbt-snowflake` pattern. ([#1412](https://github.com/databricks/dbt-databricks/pull/1412))
6+
17
## dbt-databricks 1.12.1 (June 10, 2026)
28

39
### Features

dbt/include/databricks/macros/materializations/incremental/incremental.sql

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,16 @@
5858
{{ set_overwrite_mode('DYNAMIC') }}
5959
{%- endif -%}
6060
{#-- Relation must be merged --#}
61-
{%- do process_schema_changes(on_schema_change, intermediate_relation, existing_relation) -%}
61+
{#-- Reuse the columns returned by `process_schema_changes` so the downstream
62+
merge strategy macro doesn't have to re-issue DESCRIBE on the target.
63+
When `on_schema_change == 'ignore'`, the macro returns `{}` and we fall
64+
back to a single DESCRIBE on the existing relation. --#}
65+
{%- set dest_columns = process_schema_changes(on_schema_change, intermediate_relation, existing_relation) -%}
66+
{%- if not dest_columns -%}
67+
{%- set dest_columns = adapter.get_columns_in_relation(existing_relation) -%}
68+
{%- endif -%}
6269
{{ process_config_changes(target_relation) }}
63-
{% set build_sql = get_build_sql(incremental_strategy, target_relation, intermediate_relation) %}
70+
{% set build_sql = get_build_sql(incremental_strategy, target_relation, intermediate_relation, dest_columns) %}
6471
{%- if language == 'sql' -%}
6572
{#-- Check if build_sql is a list (multi-statement strategy) or a string (single statement) --#}
6673
{%- if build_sql is sequence and build_sql is not string -%}
@@ -139,13 +146,20 @@
139146
{%- call statement('create_temp_relation', language=language) -%}
140147
{{ create_table_as(True, temp_relation, compiled_code, language) }}
141148
{%- endcall -%}
142-
{%- do process_schema_changes(on_schema_change, temp_relation, existing_relation) -%}
149+
{#-- Reuse the columns returned by `process_schema_changes` so the downstream
150+
merge strategy macro doesn't have to re-issue DESCRIBE on the target.
151+
When `on_schema_change == 'ignore'`, the macro returns `{}` and we fall
152+
back to a single DESCRIBE on the existing relation. --#}
153+
{%- set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) -%}
154+
{%- if not dest_columns -%}
155+
{%- set dest_columns = adapter.get_columns_in_relation(existing_relation) -%}
156+
{%- endif -%}
143157
{%- set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) -%}
144158
{%- set strategy_arg_dict = ({
145159
'target_relation': target_relation,
146160
'temp_relation': temp_relation,
147161
'unique_key': unique_key,
148-
'dest_columns': none,
162+
'dest_columns': dest_columns,
149163
'incremental_predicates': incremental_predicates}) -%}
150164
{%- set build_sql = strategy_sql_macro_func(strategy_arg_dict) -%}
151165
{%- if language == 'sql' -%}
@@ -225,15 +239,15 @@
225239
{% endif %}
226240
{% endmacro %}
227241

228-
{% macro get_build_sql(incremental_strategy, target_relation, intermediate_relation) %}
242+
{% macro get_build_sql(incremental_strategy, target_relation, intermediate_relation, dest_columns=none) %}
229243
{%- set unique_key = config.get('unique_key') -%}
230244
{%- set incremental_predicates = config.get('predicates') or config.get('incremental_predicates') -%}
231245
{%- set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) -%}
232246
{%- set strategy_arg_dict = ({
233247
'target_relation': target_relation,
234248
'temp_relation': intermediate_relation,
235249
'unique_key': unique_key,
236-
'dest_columns': none,
250+
'dest_columns': dest_columns,
237251
'incremental_predicates': incremental_predicates}) -%}
238252
{% do return(strategy_sql_macro_func(strategy_arg_dict)) %}
239253
{% endmacro %}

dbt/include/databricks/macros/materializations/incremental/strategies.sql

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{% endmacro %}
99

1010
{% macro databricks__get_incremental_append_sql(arg_dict) %}
11-
{% do return(get_insert_into_sql(arg_dict["temp_relation"], arg_dict["target_relation"])) %}
11+
{% do return(get_insert_into_sql(arg_dict["temp_relation"], arg_dict["target_relation"], arg_dict.get("dest_columns"))) %}
1212
{% endmacro %}
1313

1414
{% macro databricks__get_incremental_replace_where_sql(arg_dict) %}
@@ -137,7 +137,13 @@ INSERT INTO {{ target_relation.render() }}
137137
{%- set source_relation = arg_dict.get('temp_relation') -%}
138138
{%- set target_relation = arg_dict.get('target_relation') -%}
139139
{%- set incremental_predicates = config.get('incremental_predicates') -%}
140-
{%- set target_columns = (adapter.get_columns_in_relation(target_relation) | map(attribute='quoted') | list) -%}
140+
{#-- Reuse dest_columns from the materialization (obtained via `process_schema_changes`)
141+
when provided, otherwise fall back to a fresh DESCRIBE. --#}
142+
{%- set dest_columns = arg_dict.get('dest_columns') -%}
143+
{%- if dest_columns is none -%}
144+
{%- set dest_columns = adapter.get_columns_in_relation(target_relation) -%}
145+
{%- endif -%}
146+
{%- set target_columns = (dest_columns | map(attribute='quoted') | list) -%}
141147
{%- set unique_key = config.require('unique_key') -%}
142148
{% do return(delete_insert_sql_impl(source_relation, target_relation, target_columns, unique_key, incremental_predicates)) %}
143149
{% endmacro %}
@@ -218,10 +224,15 @@ where {{ incremental_predicates }}
218224
{% endmacro %}
219225

220226

221-
{% macro get_insert_into_sql(source_relation, target_relation) %}
227+
{% macro get_insert_into_sql(source_relation, target_relation, dest_columns=none) %}
222228
{%- set source_columns = adapter.get_columns_in_relation(source_relation) | map(attribute="name") | list -%}
223-
{%- set dest_columns = adapter.get_columns_in_relation(target_relation) | map(attribute="name") | list -%}
224-
{{ insert_into_sql_impl(target_relation, dest_columns, source_relation, source_columns) }}
229+
{#-- Reuse dest_columns from the materialization when provided; otherwise DESCRIBE. --#}
230+
{%- if dest_columns is none -%}
231+
{%- set dest_cols_list = adapter.get_columns_in_relation(target_relation) | map(attribute="name") | list -%}
232+
{%- else -%}
233+
{%- set dest_cols_list = dest_columns | map(attribute="name") | list -%}
234+
{%- endif -%}
235+
{{ insert_into_sql_impl(target_relation, dest_cols_list, source_relation, source_columns) }}
225236
{% endmacro %}
226237

227238
{% macro insert_into_sql_impl(target_relation, dest_columns, source_relation, source_columns) %}
@@ -272,7 +283,12 @@ where {{ incremental_predicates }}
272283
{%- set source_alias = config.get('source_alias', 'DBT_INTERNAL_SOURCE') -%}
273284

274285
{%- set predicates = [] if incremental_predicates is none else [] + incremental_predicates -%}
275-
{%- set dest_columns = adapter.get_columns_in_relation(target) -%}
286+
{#-- Prefer the `dest_columns` passed in by the materialization (obtained via
287+
`process_schema_changes` or a single DESCRIBE on the existing relation).
288+
Only issue a fresh DESCRIBE when no columns were provided. --#}
289+
{%- if dest_columns is none -%}
290+
{%- set dest_columns = adapter.get_columns_in_relation(target) -%}
291+
{%- endif -%}
276292
{%- set source_columns = (adapter.get_columns_in_relation(source) | map(attribute='name') | list)-%}
277293
{%- set merge_update_columns = config.get('merge_update_columns') -%}
278294
{%- set merge_exclude_columns = config.get('merge_exclude_columns') -%}

0 commit comments

Comments
 (0)