Guides

How to reduce data warehouse costs

Where usage-based warehouse spend actually goes, and the levers — query, storage, scheduling — that reliably bring it down.

Cloud data warehouse bills grow quietly. Nobody approves a large increase at once; a new dashboard here, a nightly job that got heavier there, and a year later the bill has doubled with no single change anyone can point to. Because Snowflake, BigQuery, Databricks and Redshift all bill some combination of compute time and data scanned, the levers that bring cost down are the same levers that make queries faster — cost and performance work reduce together here, which is unusual and worth using.

Find out where the money actually goes first

Before changing anything, get a breakdown by query, by user or service account, and by scheduled job. Every major warehouse exposes this in its account usage or billing views. The typical finding is a small number of jobs responsible for most of the spend: a handful of dashboards that re-scan a huge table on every page load, a nightly transformation job that rebuilds everything from scratch instead of processing only what changed, or one analyst's habit of running select * on a multi-terabyte table to "take a quick look."

Optimizing the wrong ten queries wastes effort; optimizing the top five by cost usually captures most of the achievable savings. Keep this breakdown visible on an ongoing basis rather than pulling it once for a single cleanup project — costs creep back in as new dashboards and pipelines are added, and a one-time audit only buys a temporary reduction if nothing keeps watching afterward.

Lever 1: scan less data

Warehouses that bill by data scanned (BigQuery, Redshift Serverless, Snowflake's larger warehouses under heavy concurrency) reward queries that touch less data, not just faster ones.

  • Partition and cluster large tables by the columns queries actually filter on — usually a date column. A query with a where order_date >= '2026-01-01' against a table partitioned by order_date scans only the relevant partitions instead of the whole table.
  • Select only the columns you need. Warehouses use columnar storage, so select order_id, amount scans only those two columns' data, while select * scans everything even if you only look at two columns afterward.
  • Avoid scanning raw, ungrouped event tables repeatedly for aggregates that do not change intraday. Pre-aggregate once into a smaller table.
-- scans only the touched partition, and only two columns
select order_id, amount
from fct_orders
where order_date = current_date - 1

Lever 2: compute less, by materializing and incrementally building

Rebuilding a large transformation from scratch on every run is the single most common source of avoidable spend in a modern stack. An incremental model — in dbt or any transformation tool — processes only new or changed rows since the last run, instead of reprocessing history every time.

-- dbt incremental model: only process rows newer than the last run
{{
  config(materialized='incremental', unique_key='order_id')
}}
select *
from {{ ref('stg_orders') }}
{% if is_incremental() %}
where order_date > (select max(order_date) from {{ this }})
{% endif %}

For dashboards that repeatedly query the same expensive aggregation, a materialized view — computed once, on a schedule, and read many times — trades a small, predictable refresh cost for eliminating the repeated cost of recomputing on every page load.

Lever 3: right-size and schedule compute

Warehouses that bill by cluster or warehouse size (Snowflake's virtual warehouses, Redshift's provisioned clusters) waste money two ways: oversized compute running underused, and compute left running when nobody is querying.

  • Auto-suspend idle compute. A warehouse that suspends after a few minutes of inactivity and resumes on the next query costs nothing while idle — the resume delay is usually seconds, a reasonable trade for most workloads.
  • Separate workloads by size. A small warehouse for ad hoc analyst queries and dashboards, a larger one scheduled only for the nightly transformation batch, rather than one large warehouse sized for the peak and running that size all day.
  • Schedule heavy batch jobs off-peak where pricing or contention rewards it, and stagger jobs that do not need to finish at the same minute.

Lever 4: reduce redundant copies

Each additional environment (dev, staging, a data science sandbox) that fully copies production data multiplies both storage and the compute spent refreshing it. zero-copy data sharing, where supported, lets a second environment query the same underlying data without physically duplicating it, cutting both storage cost and refresh compute.

Similarly, check for the same source table loaded twice by two different pipelines because two teams did not know about each other's connector — a common outcome as an ELT stack grows without central visibility into what already exists.

Lever 5: govern who can run what

Cost problems recur when nobody sees the bill until it arrives. Two controls that hold gains once you have made them:

  • Per-team or per-project cost attribution, using tags or separate warehouses/projects, so a spike is traceable to an owner within a day, not discovered at month end.
  • Query cost limits or alerts on ad hoc environments, so one runaway query from a notebook cannot silently burn a month's budget in an afternoon.

What does not usually work

Switching vendors chasing a lower headline price rarely produces lasting savings if the same inefficient queries and full-table rebuilds move with you — the same five expensive jobs will be expensive on the new platform too, just measured in a different currency. Optimize the workload first; a migration is a much larger project and should be justified on its own terms, not as a shortcut around query optimization.

A short checklist

  1. Get a cost breakdown by query and job; find the top five by spend.
  2. Partition and cluster the largest scanned tables.
  3. Convert full-rebuild transformations to incremental where the source only appends or updates.
  4. Materialize expensive, repeatedly-queried aggregations.
  5. Auto-suspend idle compute and size warehouses to the workload, not the peak.
  6. Attribute cost to a team or project so the next spike is caught quickly.

This work pairs naturally with building a modern data stack and with a metrics layer, since pre-aggregated, well-modeled metrics are cheaper to query as well as more consistent. Warehouse and lakehouse platforms are browsable at cloud data warehouses and lakehouse platforms and table formats; see also Amazon Redshift vs Snowflake and Google BigQuery vs Snowflake for platform-level trade-offs.

Related tools

Terms used in this guide

Latest on this topic