04 Rebuild the dbt pipeline
Facilitator guide for rebuilding the dbt pipeline on ClickHouse — why the empty aggregate table is not a bug.
Facilitator companion to the learner lesson 04 Rebuild the dbt pipeline.
Timing
About 30 minutes. The only stretch with real dead air is the second dbt run in Step 1
(roughly 8-12 minutes to process 50 million rows through the incremental models) — short
enough that it usually doesn't need a break of its own, but long enough to narrate rather
than watch in silence. Step 2 (the zone dictionary) and the verification queries are
quick and interactive.
Talk track
- Frame this module as proving the pipeline, not the data: module 03 proved ClickHouse can hold 50 million rows; this module proves the same Medallion pipeline from module 01 — staging views, incremental fact table, dimension reloads, tests — runs unchanged in shape on ClickHouse.
- The one dbt mechanism worth pausing on:
delete_insertreplacesMERGE INTO(ClickHouse has noMERGEstatement), andReplacingMergeTreeis the safety net underneath it, not a substitute for it — ifdelete_insertcompletes normally there is nothing for RMT to clean up; it only matters if a run is interrupted mid-way. mv_live_trip_feedis worth calling out by name: it has no Snowflake counterpart at all. A standard materialized view only ever sees the rows in the batch that triggered it; a REFRESHABLE materialized view re-runs its whole query on a schedule, so it can maintain a lifetime aggregate. This is new capability the migration adds, not a straight port.- Say this before anyone asks:
agg_hourly_zone_tripswill be empty after Step 1'sdbt run, and that is correct, not a bug. Its incremental filter isWHERE pickup_at >= now() - INTERVAL 2 HOUR, which only matches rows written by a live producer; every row just migrated is historical. It stays empty until module 05 starts the ClickHouse producer at cutover. Partners reliably assume this is a broken pipeline — get ahead of the question.
Common failures
agg_hourly_zone_tripsreturns 0 rows after Step 1, and a partner reports it as a bug. It is not — see the talk track above. Confirmdim_taxi_zones(265 rows) andfact_trips(roughly 50 million rows) are populated as expected before spending any time onagg_hourly_zone_trips; if those two are correct, the empty aggregate table is working exactly as designed. This is the module's headline failure — expect the question every time.dbt runin Step 1 fails or cannot connect. This module depends on the ClickHouse dbt profile module 03 should already have created (~/.dbt/profiles.yml,nyc_taxi_ch). If that profile is missing — see Step 2's "Configure the dbt profile" in 03 Provision and migrate — Step 1 fails here instead, one module later than the root cause.- TODO: the site's
Troubleshooting page's
## dbt on ClickHousesection has no dedicated entry for a failure that surfaces only at this step. Capture anything rehearsal-specific here.
Reset steps
- Re-run
dbt runfreely — it is incremental and safe to repeat; nothing here needs a teardown. - After a dbt model or schema change, force a full rebuild of the incremental models:
dbt run --full-refresh(fromworkshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/dbt/nyc_taxi_dbt_ch). - If the zone dictionary looks wrong or stale, just re-run
scripts/04_create_dictionary.sql— it isCREATE OR REPLACE DICTIONARY, safe to run again without dropping anything first. - No environment-level reset applies here — this module's teardown is the same
workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/teardown.shcovered under module 03; do not run it mid-module.
03 Provision and migrate
Facilitator guide for the ClickHouse provisioning and migration module — the 40 to 50 minute unattended transfer and the missing dbt profile.
05 Benchmark and cutover
Facilitator guide for benchmarking and cutover — the two-pass gap closure, dashboard import pitfalls, and teardown order.