Snowflake cost monitoring means turning the account’s own telemetry into a bill
you can explain. Everything you need is already in the
SNOWFLAKE.ACCOUNT_USAGE schema: WAREHOUSE_METERING_HISTORY for credits per
warehouse, QUERY_HISTORY for per-query attribution, and
METERING_DAILY_HISTORY for the daily account total. Add resource monitors
and budgets for alerting, and you can see — to the credit — where the money
goes. What monitoring can’t do is spend less for you.
Most teams discover their Snowflake bill is too high long before they can say why. The fix is not another invoice line item; it’s a habit of querying the account’s metering views, attributing spend, and watching trends with alerts. This post walks the views that matter, the difference between resource monitors and budgets, a set of starter cost queries you can paste in today, and the honest limit of dashboards — they explain the bill, but they sit outside the query path and never act on it.
01 / THE VIEWS THAT MATTERWhich ACCOUNT_USAGE views should I monitor?
Snowflake bills you for compute (credits burned by warehouses) and a smaller
amount for storage and cloud services. For cost monitoring, three
ACCOUNT_USAGE views carry almost all the signal:
| View | Grain | What it answers |
|---|---|---|
WAREHOUSE_METERING_HISTORY | Hourly, per warehouse | Which warehouses burn the most credits, and when |
QUERY_HISTORY | Per query | Who ran what, on which warehouse, scanning how much, for how long |
METERING_DAILY_HISTORY | Daily, whole account | Total credits/day across compute, storage, and cloud services |
A practical split: METERING_DAILY_HISTORY is your top-line trend line,
WAREHOUSE_METERING_HISTORY tells you which warehouse moved it, and
QUERY_HISTORY lets you drill all the way to the user, app, BI tool, or dbt
model that owns the spend. (For chargeback mechanics, see
Snowflake cost attribution and chargeback.)
Mind the latency. ACCOUNT_USAGE views have ingestion lag — typically up to
~45 minutes for metering and ~45 minutes for query history, with up to 24 hours
of total data freshness. They’re authoritative for trends and chargeback, not
for real-time interception. That latency is exactly why monitoring observes but
can’t act in flight.
02 / RESOURCE MONITOR VS BUDGETResource monitor vs budget — what’s the difference?
These two controls get conflated constantly, but they do different jobs.
A resource monitor is an enforcement control. You give it a credit quota over an interval (e.g. monthly) and attach triggers: at 75% of quota, notify; at 90%, notify; at 100%, suspend the warehouse after running queries finish; at 110%, suspend immediately and cancel running queries. It can actually stop compute. The cost: it’s blunt — it kills the warehouse, not the wasteful workload.
A budget is a tracking and alerting control. You set a spend target, attach the objects (warehouses, databases, etc.) you want to watch, and Snowflake notifies account admins when projected or actual spend crosses the target. A budget never suspends anything. It’s the early-warning system; the resource monitor is the circuit breaker.
Use a resource monitor to stop runaway compute. Use a budget to see the runaway coming. Neither makes the underlying workload cheaper.
— rule of thumb
| Resource monitor | Budget | |
|---|---|---|
| Primary job | Cap & suspend compute | Track spend vs target |
| Can suspend warehouses? | Yes (at thresholds) | No |
| Granularity | Account or per-warehouse | Group of objects |
| Best for | Hard guardrails | Trend alerts, forecasting |
In practice you want both: budgets so finance gets warned early, resource monitors so a runaway dashboard or a misfiring ELT job can’t drain a month of credits overnight.
03 / STARTER COST QUERIESWhat SQL should I run first?
Two queries cover 80% of the first investigation: which warehouses cost the
most, and which queries are the most expensive to run. Both read straight from
ACCOUNT_USAGE.
-- Top warehouses by credits, last 30 days
SELECT
warehouse_name,
ROUND(SUM(credits_used), 1) AS credits,
ROUND(SUM(credits_used) * 3.00, 0) AS approx_usd -- swap in your $/credit
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
WHERE start_time >= DATEADD('day', -30, CURRENT_TIMESTAMP())
GROUP BY warehouse_name
ORDER BY credits DESC;
-- Most expensive query shapes, last 30 days (by total execution time)
SELECT
LEFT(query_text, 80) AS query_preview,
COUNT(*) AS runs,
ROUND(SUM(execution_time) / 1000 / 60, 1) AS total_exec_minutes,
ROUND(AVG(bytes_scanned) / POWER(1024, 3), 2) AS avg_gb_scanned,
SUM(IFF(warehouse_size IS NOT NULL, 1, 0)) AS warehouse_runs
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= DATEADD('day', -30, CURRENT_TIMESTAMP())
AND execution_status = 'SUCCESS'
GROUP BY query_preview
ORDER BY total_exec_minutes DESC
LIMIT 50;
The warehouse query gives you the credit leaderboard; the query-shape query tells you whether spend is concentrated in a few monster transforms or — far more common on BI-heavy accounts — spread across thousands of cheap, repeated reads. That distinction decides what to do next, and it’s where how much Snowflake actually costs becomes a question with a real answer.
04 / DASHBOARDS EXPLAIN, THEY DON’T ACTWhy does monitoring not reduce my bill?
This is the structural limit every cost dashboard shares — whether it’s a
homegrown Looker board, dbt-snowflake-monitoring, or a hosted analytics tool.
They read ACCOUNT_USAGE after the credits are spent. By design they sit
outside the query path: they can show you that the same dashboard query ran
40,000 times last month, but they can’t serve any of those 40,000 from a cache,
can’t suspend the warehouse a few minutes earlier, and can’t rewrite an
expensive query shape in flight. Observation and action are different layers.
That’s not a knock on monitoring — you can’t fix what you can’t see, and these queries are the right first move. It’s just the honest ceiling: a report explains the bill; it doesn’t shrink it. To shrink it you need something in the path that can make a decision per query, before the warehouse wakes up.
05 / FROM MONITORING TO IN-PATH ACTIONHow do you turn visibility into savings?
This is the bridge from observing spend to cutting it. chukei is an open source, Apache-2.0, self-hosted Snowflake cost optimization engine — a transparent wire-protocol proxy that runs in your own VPC. Drivers change one hostname and nothing else; your SQL and credentials stay exactly where they are. Because it sits in the query path, it can act on the very patterns your monitoring surfaced:
- Verified result caching serves deterministic repeated reads from a cache that is continuously double-checked against live Snowflake (soak run: ~120k queries, ~60k cache hits, 0 mismatches).
- Warehouse auto-suspend uses a Poisson idle model to recommend safe early suspends — it captured ~94% of modelled savings in simulation.
- Deterministic SQL rewriting applies equivalence-tested rules inline. There is no LLM on the hot path — the decision is deterministic, with ~2 ms p99 added overhead.
- Per-team cost attribution stamps every query at the wire with the user, app, team, or dbt model that owns it — the same chargeback your QUERY_HISTORY drill-downs were approximating, but live.
Fail open, always. Parse errors, cache misses, non-deterministic SQL, writes, and unsafe result shapes all degrade to a byte-identical passthrough to Snowflake. The cache is false-positive-intolerant — when in doubt, it misses. chukei never breaks a query.
You don’t have to take the savings range on faith. The replay simulator
reads a CSV export of your QUERY_HISTORY, simulates every lever offline, and
emits an Ed25519-signed evidence file — nothing installed in the path, nothing
leaving your machine.
# export a month of history from Snowflake, then:
chukei replay --query-history queries.csv --evidence report.json
✓ parsed 4,210,773 queries (31 days)
✓ cache deterministic repeats identified
✓ suspend idle windows modelled (Poisson)
→ projected savings within 15–30% target band
✓ wrote signed report.json · Ed25519
The 15–30% figure is a target to validate via replay, never a guarantee — the real number depends on your workload mix and how well your warehouses are already tuned. Monitoring tells you where the money goes; replay tells you how much of it is recoverable before you change a thing. For the full picture of levers and rollout, start with the cornerstone guide to Snowflake cost optimization.
Key takeaways
- Monitor from
ACCOUNT_USAGE: WAREHOUSE_METERING_HISTORY (credits by warehouse), QUERY_HISTORY (per-query attribution), METERING_DAILY_HISTORY (daily totals). - Resource monitor vs budget: a resource monitor caps and suspends compute; a budget tracks and alerts but never suspends. Use both.
- Start with two queries: top warehouses by credits, and most expensive query shapes — they reveal whether spend is a few monsters or a thousand repeats.
- Dashboards explain, they don’t act: they read telemetry after the fact, outside the query path, so they can’t cache, suspend, or rewrite in flight.
- Bridge to action: an in-path engine like chukei turns the patterns you monitored into savings — validated first with a signed replay, never promised.
Build the visibility first; the queries above are a complete starting point. When you’re ready to act on what you find, run the replay against your own history and read the receipts — it’s all in the repository.
Frequently asked questions
- How do I monitor Snowflake costs?
- Query the SNOWFLAKE.ACCOUNT_USAGE views — WAREHOUSE_METERING_HISTORY for credits by warehouse, QUERY_HISTORY for per-query attribution, and METERING_DAILY_HISTORY for daily account totals. Layer resource monitors and budgets on top for alerting, and surface the results in a BI dashboard.
- What is QUERY_HISTORY used for?
- QUERY_HISTORY records every query run on the account — text, user, warehouse, bytes scanned, execution time, and queuing. It's the source of truth for attributing cost to users, teams, BI tools, and dbt models, and for finding the most expensive query shapes.
- Resource monitor vs budget — what's the difference?
- A resource monitor caps warehouse credit consumption and can notify, suspend, or hard-suspend warehouses when a quota is hit — it's an enforcement control. A budget tracks spend against a target across a group of objects and alerts you, but never suspends anything. Use resource monitors to stop runaway compute; use budgets to watch trends and get warned early.
- How do I set a Snowflake spend alert?
- Create a resource monitor with a credit quota and a NOTIFY trigger at a percentage threshold, or create a budget and attach it to the objects you want to watch. Both can email account admins; resource monitors can additionally suspend warehouses at higher thresholds.
- Does monitoring reduce my Snowflake bill on its own?
- No. Monitoring and dashboards observe spend — they explain where credits go but sit outside the query path, so they can't serve a result, suspend an idle warehouse, or rewrite a query in flight. Reducing the bill needs an action layer; monitoring tells you where to point it.
Builds the Rust wire-protocol core of chukei. Spends his time making sure the proxy adds milliseconds, never breakage.