Say this first: Build a small set of owned materialized views at the grains the dashboards actually use, refreshed on data arrival, and point every dashboard at those rather than at silver.
Remember these
- Derive the grains to materialize from query history, not from requests
- Keep definitions pure so refresh stays incremental
- Define them in bundles owned by service principals, not in the editor
- Retire views whose refresh cost exceeds the query cost they avoid
Why: Start from query history: group the warehouse's expensive queries by shape and find the handful of grains that account for most of the aggregation cost. Materialize those, deliberately and with owners, so one refresh replaces thousands of ad hoc recomputations. Keep the definitions free of time-dependent expressions so refresh stays incremental, and drive refresh from the loading pipelines rather than from clocks. The governance half matters as much: define the materialized views in asset bundles owned by service principals, so they are reviewed, deployed, and attributable, and so a departing employee does not take a gold table's refresh with them. Then watch two numbers — refresh cost per view, and warehouse cost avoided — and retire views whose refresh costs more than the queries they replaced, because a stale unused materialized view is pure spend.
SELECT statement_text, COUNT(*) AS runs, SUM(total_duration_ms)/1000 AS secs
FROM system.query.history
WHERE start_time >= current_date() - INTERVAL 7 DAYS
GROUP BY ALL ORDER BY secs DESC LIMIT 20
Senior depth: The trap in a serving layer is that materialized views are easy to create and nobody ever deletes one. So I design it as a small, owned, versioned set — a dozen grains, not two hundred — and make adding one a review conversation about whether an existing grain covers it. Then I keep a standing report of refresh cost per view against the read traffic it serves, and I retire the bottom of that list every quarter. Without that loop you end up paying continuously to keep results fresh for dashboards that were decommissioned a year ago.
Common mistake: Creating a materialized view per dashboard on request, ending with hundreds of overlapping refreshes nobody owns.
Follow-up they will ask: How would you find the materialized views that are no longer worth refreshing?