Skip to content

dbt Core 2.0 parity: Materialization materialized_view #705

Closed

Description

@koletzilla

Sub-issue of #660 — feature-parity tracking for the ClickHouse adapter in dbt Core 2.0 / Fusion versus the Python dbt-clickhouse adapter.

Covers the materialized_view materialization, separated by (EX)plicit and (IM)plicit target variants. Creation paths (base create, derivative, catchup, refreshable clause, external targets, multi-MV create, MODIFY QUERY updates) and the re-run intelligence (refresh-schedule updates, MV-target protection, multi-MV update/rename, on_schema_change, refreshable: false) work on main (dbt-labs/dbt#15507, #16200): the materialization is done for v1 parity. The proper upstream multi-MV design and the refreshable catch-up ordering fix are ⚪️ future work (#731).

Status legend:

  • ✅ implemented — merged and working on dbt-core 2.0 origin/main
  • 🟡 partial — partly working on origin/main; Notes say what works vs fails
  • 🚧 in progress — implemented in an open PR (linked in Notes)
  • 🔴 not started — not working anywhere
  • ⚪️ future work — explicitly deferred, not being solved now (also listed in the future-work sub-issue)
Feature Subfeatures / details Status Notes (PR)
Materialization: materialized_view (overall) ✅ dbt-labs/dbt#15507 (create paths, MODIFY QUERY, refreshable clause, catchup, external targets) + dbt-labs/dbt#16200 (refresh-schedule updates, target protection, multi-MV updates, on_schema_change, refreshable: false). Deferred: refreshable catch-up ordering (#731)
Base create (MV + target table) Creates the MV and its target in implicit mode ✅ dbt-labs/dbt#15507
(IM)relation.derivative(suffix, type, …) Rust relation method used to derive the <model>_mv relation ✅ dbt-labs/dbt#15507, with unit tests
catchup config Default/True backfill; False = empty target + live trigger ✅ dbt-labs/dbt#15507. catchup=false on a model that also declares projections via dbt-labs/dbt#16200
refreshable config (map form) {interval, randomize, append, depends_on, depends_on_validation} → REFRESH clause at CREATE time ✅ dbt-labs/dbt#15507. Changing the schedule of an existing MV is the lifecycle row below
refreshable.depends_on_validation Existence check of dependencies via system.view_refreshes ✅ validate_refreshable_mv_existence
MV update/replace on re-run ALTER TABLE … MODIFY QUERY for a changed SELECT; drop+create fallback ✅ dbt-labs/dbt#15507. Refresh parameters and mv_on_schema_change/repopulate are the rows below
External target table materialization_target_table(ref(...)) ✅ Create, MODIFY QUERY re-run, live propagation and catchup insert work; changing the TO target errors with a --full-refresh hint. Target-change validation and query-only updates via mvs_pointing_to_it + can_exchange (dbt-labs/dbt#16200)
Auto-drop of auto-created MV on materialization switch Model changes from materialized_view to view → leftover <model>_mv dropped, non-dbt MVs get a warning ✅ clickhouse__drop_associated_mv_if_it_was_automatically_created, called from view.sql. Same limitations as v1: single-MV, current database only
Refreshable MV re-run lifecycle ALTER TABLE … MODIFY REFRESH on re-run (upstream #611); errors for in-place regular↔refreshable and APPEND↔non-APPEND transitions ✅ dbt-labs/dbt#16200 (clickhouse__modify_mv_refresh + is_refreshable/refreshable_append relation state)
refreshable: false (bare bool form) false behaves exactly like omitting the key; bare true must keep erroring "must be a dictionary" (v1 parity) ✅ dbt-labs/dbt#16200 (RefreshableConfig bool|map + the macro guard)
Refreshable MV catch-up vs the first refresh With catchup: true (the default) dbt's backfill insert and the view's initial refresh write the target at the same time ⚪️ Deferred (#731). A non-APPEND refreshable view can lose the backfilled rows (or fail with TABLE_IS_READ_ONLY on Cloud) and an APPEND view holds every row twice; workaround: catchup: false and let the first refresh fill the target
Related to Implicit target feature ✅
Multiple MVs per model --<name>:begin / --<name>:end SQL splitting → one <model>_<name> MV each ✅ Fresh create of N MVs (dbt-labs/dbt#15507); update/rename flows (marker parsing, rename detection via mvs_pointing_to_it) in dbt-labs/dbt#16200. The upstream-design-dependent proper fix is ⚪️ future work (#731)
Stale/renamed-MV detection Warn about MVs pointing at the target that are no longer in the model; recognize dbt-managed (incl. aliased) MVs ✅ Warning on replace (clickhouse__search_associated_mvs_to_target); alias-aware recognition via mvs_pointing_to_it (dbt-labs/dbt#16200)
Robust multi-MV marker parsing clickhouse__extract_mv_views (single-token marker names, upstream #683) ✅ dbt-labs/dbt#16200
on_schema_change support append / sync / fail on the MV target ✅ Adapter method check_incremental_schema_changes(…, materialization='materialized view') in dbt-labs/dbt#16090; the MV-side wiring in dbt-labs/dbt#16200
Related to Explicit target feature ✅
Target table protection mv_on_schema_change (defaults to fail when a dbt MV points at the table) + repopulate_from_mvs_on_full_refresh via relation.mvs_pointing_to_it ✅ Config keys registered (dbt-labs/dbt#15507) and consumer macro merged; catalog stamping of mvs_pointing_to_it and the table.sql behaviour in dbt-labs/dbt#16200

Activity

  1. koletzilla commented on Sep 8, 2026

    @koletzilla
    ContributorAuthor

    Closing: the materialized_view materialization is at v1 parity on dbt Core 2.0 main (refresh-schedule updates, MV-target protection, multi-MV update/rename, on_schema_change and refreshable: false landed with dbt-labs/dbt#16200). The proper upstream multi-MV design stays as future work in #731; remaining gaps are cross-materialization (#711).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions