Warehouse Cost Control: The Quarterly Ritual
- The most expensive query is rarely a single bad query; it is a small query running 100,000 times per day.
- Half of the materialised tables in a typical warehouse have not been queried in the last 30 days.
- Dashboards that are never opened still pull data on schedule. Stop the schedule.
- Per-team or per-product cost attribution is the only honest baseline for prioritisation.
A finance team forwarded an email to engineering: “the warehouse bill grew 47 percent this quarter, please explain”. The data team had no immediate answer. They knew usage had grown but not by 47 percent. The investigation took two weeks. The cause was not exotic: a dashboard a marketing team had set up six months earlier was running a 800-million-row scan every 15 minutes, on a schedule, regardless of whether anyone opened the dashboard. Nobody had opened the dashboard in three months. The cost of that single dashboard was roughly 18,000 dollars per quarter.
We spent another month with the team installing the cost-control discipline that catches this kind of issue before the next quarter. The next quarterly bill came in 31 percent below the previous one despite usage continuing to grow. The savings were structural, not heroic.
This piece is about the ritual. The quarterly process that keeps warehouse cost predictable and prevents the kind of surprise that produces emergency cost-cutting projects.
What grows the bill
Warehouse spend has a small number of drivers. In rough order of impact:
Compute on scheduled queries. Materialised views, dbt jobs, scheduled extracts, dashboard refreshes. These run regardless of whether anyone needs the result. A poorly-tuned schedule costs every day.
Ad-hoc analyst queries. Less predictable but often less total cost than scheduled. The exception is the famous “let me just run this on production” query that scans a billion rows and runs for an hour.
Storage of redundant tables. Same data, modelled differently, materialised in three places. Storage is cheap until it isn’t; at scale it adds up.
Cross-region or cross-cloud egress. Often invisible until a multi-cloud architecture surfaces it. Egress fees are some of the highest unit costs in cloud billing.
The quarterly ritual surfaces each of these.
The quarterly ritual, in five steps
Step 1: pull the top 10 most expensive queries by total spend.
Most warehouses provide a query history table with cost per execution. Aggregate by query hash or query template:
-- Snowflake example
SELECT
query_hash,
ANY_VALUE(query_text) AS sample_text,
COUNT(*) AS executions,
SUM(credits_used_cloud_services + credits_used_compute) AS total_credits
FROM snowflake.account_usage.query_history
WHERE start_time >= DATEADD(quarter, -1, CURRENT_DATE)
GROUP BY query_hash
ORDER BY total_credits DESC
LIMIT 10;
The top 10 are almost never bad ad-hoc queries. They are usually scheduled queries running thousands of times per quarter, each one cheap individually. This is where the leverage is.
Step 2: pull the top 10 most expensive tables by storage and access.
Similar query against the warehouse’s metadata. For each table:
- Storage cost per quarter
- Number of queries against it per quarter
- Last query timestamp
Tables that cost storage but have not been queried recently are candidates for archive or deletion.
Step 3: identify dashboards by access frequency.
Most BI tools (Looker, Tableau, Metabase, Mode) log dashboard access. Pull the access log:
- Dashboards opened in the last 30 days
- Dashboards opened in the last 90 days
- Dashboards never opened
Cross-reference with the dashboards’ refresh schedules. A dashboard refreshing every 15 minutes that nobody has opened in 60 days is a pure cost.
Step 4: attribute spend by team or product.
Tag every query with a team identifier (via warehouse user/role mapping) and aggregate. Without per-team attribution, optimisation conversations are vague (“we should reduce spend”). With it, conversations become specific (“the marketing team is spending $X per quarter on dashboards used by 2 people; the platform team is spending $Y on production-required pipelines”).
Step 5: action the findings.
For each finding, one of:
- Fix the query (add a filter, materialise an aggregate, optimise the plan)
- Change the schedule (less frequent refresh, off-peak)
- Delete the table or dashboard
- Move the workload to a smaller warehouse tier
- Negotiate cost differently (reserve capacity, change the cluster sizing)
Track the actions. The ritual produces nothing if findings sit in a document.
What kills the ritual
Three patterns we see consistently:
Doing it once. A team runs the audit once, makes the obvious cuts, declares victory. Three quarters later the bill has crept back. The ritual is quarterly because the entropy is quarterly.
Owning it nowhere. “We should do a cost audit” with no named owner means it does not happen. The owner can be a data engineer, a platform lead, or a product analyst; they need to be named, and 1-2 days per quarter need to be reserved.
Acting only on the top query. The top single query is usually less than 5 percent of the bill. The top 10 queries are usually 30-50 percent. The next 100 queries are the rest. Optimising the top 10 is the leverage; ignoring the long tail is fine; but stopping at the top 1 is leaving most of the savings on the table.
Discipline that prevents the regression
Some patterns prevent the bill from growing in the first place:
Scheduled query reviews. Any new scheduled query goes through a small review (cost estimate, refresh frequency justification, owner). Without review, schedules accumulate.
Dashboard sunset policy. Dashboards not opened in 90 days are auto-paused. Owner gets notified; they can re-enable if needed. Without auto-pause, deprecated dashboards live forever.
Query budget per user/role. Some warehouses (Snowflake’s resource monitors, BigQuery’s reservation slots) let you set per-user spending caps. Useful for analyst environments where one rogue query can be expensive.
Cost in the PR. When dbt models are added or changed, the PR shows the estimated cost impact. The team learns to think about cost at design time instead of at the quarterly review.
What about reserved capacity?
Snowflake and BigQuery both offer reserved capacity contracts at meaningful discounts (20-40 percent off pay-as-you-go). Worth signing if:
- Usage is predictable and growing (you’ll consume the commitment)
- The contract term aligns with your business horizon
- The discount more than offsets the lost flexibility
Not worth it if usage is spiky, if the contract locks you into a vendor decision you might want to revisit, or if the discount is offered only at commitment levels far above current usage.
The longer-term shape
Teams that run the ritual consistently for a year see a noticeable shift: cost growth becomes proportional to data growth, not faster. The bill stops surprising the CFO. Engineering can have honest conversations about cost trade-offs because the numbers are visible.
Teams that do not run it see the opposite. Cost grows faster than data growth as inefficient queries accrete. The first surprise bill triggers a panic project. The panic project produces some savings but no durable discipline. Six months later, the bill is back where it was.
The ritual is small. One person, two days per quarter, with the right SQL and the right access. The compounding effect over years is the difference between a warehouse that scales with the business and a warehouse that quietly absorbs more of the budget than anyone planned for.
Questions teams ask
Should we move from Snowflake to BigQuery (or vice versa) to save money?
Almost never the right move. The migration cost (3-12 months of work) usually exceeds the price difference. Optimise within your existing platform first; switch only if a fundamental capability is missing.
Are reserved capacity contracts worth it?
Yes if your usage is predictable enough that you'll consume the commitment. No if usage spikes and dips significantly. Check the historical usage curve before signing.
How do we handle ad-hoc analyst queries?
Smaller dedicated warehouse for analysts (often 5-10x cheaper than running their queries on the production warehouse). Bigger queries that scan production tables get scheduled or routed through pre-aggregated views.