DataLane
(updated )10 min readTools

Snowflake vs BigQuery: Credits vs Bytes Scanned

The pricing models decide the architecture: warehouse-hours versus on-demand scans, plus multi-cloud vs GCP-native gravity.

By Dinesh Chandra

Illustrated overview of Snowflake vs BigQuery: Credits vs Bytes Scanned
Table of contents

If you remember one difference: BigQuery charges for bytes a query reads; Snowflake charges for seconds a warehouse is awake.

Everything else — dialects, sharing, multi-cloud, “serverless” — is downstream of that. Teams that treat this as a logo contest rewrite the platform in two years. Teams that treat it as a billing model pick once and tune the right knobs.

flowchart LR
  bq[BigQuery] --> scan[Bytes scanned × rate]
  sf[Snowflake] --> wh[Warehouse size × time]

Two invoices, two optimization cultures

On-demand BigQuery is a scan tax. Partition, cluster, select columns, stop SELECT * on a late-arriving fact table. A query that finishes in 2 seconds on 40 TB still bills 40 TB if it read 40 TB. Slot reservations and editions change how you pay (capacity vs on-demand) but they do not make an unpartitioned full scan virtuous. Details that actually move the number: partitioning and clustering.

Snowflake is a runtime tax. A tiny query on a Large warehouse costs Large × time. A well-pruned query on a warehouse that never suspends costs idle. Auto-suspend, right-size, split BI from transform. Details: Snowflake cost techniques.

If you move a workload from BQ to Snowflake and keep “scan paranoia” but leave a warehouse at Medium all day, you will call Snowflake expensive. If you move the other way and keep “warehouse thinking” but never partition, you will call BigQuery a surprise.

Lever BigQuery Snowflake
First knob Partition + cluster + column prune Auto-suspend + warehouse size
Disaster query SELECT * on an unpartitioned fact Warehouse left running / oversized
Concurrency Slots / reservations / editions Multi-cluster warehouses
Storage Cheap-ish; time travel / copies still exist Cheap-ish; Time Travel retention is the quiet bill
Predictability On-demand varies with scan; reservations flatten Credits flatten if warehouses are disciplined

Do not quote a blog’s “typical $/TB” or “typical $/credit” into a board deck. Use your contract, your region, and a week of INFORMATION_SCHEMA / ACCOUNT_USAGE.

Architecture gravity

BigQuery lives on GCP. Pub/Sub, Dataflow, GCS, Vertex, IAM — the joins are boring in a good way. Leaving GCP with the data in BQ is possible (extract, Omni, partner tools) and always a project.

Snowflake lives where you put the account (AWS, Azure, GCP). Storage and compute stay in that cloud. Multi-cloud accounts are a real pattern (a GCP account for a GCP-native source, an AWS account for the enterprise warehouse). That is still two Snowflake accounts and replication, not magic.

GCP-native path:
  Pub/Sub → Dataflow → GCS / BQ → scheduled queries / dbt

Snowflake path:
  COPY / Snowpipe / Kafka → stage → native or Iceberg tables → dbt

Neither path is “modern.” Both are production if the grain is honest and the bill has an owner.

When BigQuery is simpler

  • The rest of the stack is already GCP.
  • Analysts are fine with GoogleSQL and the BQ console / Looker / connected sheets.
  • You want SQL without a warehouse to size. Serverless is real for the query engine. It is not real for cost — bytes still bill.
  • Streaming inserts / storage write API into fact tables that you then query with partition filters.
  • Analytics Hub / dataset sharing inside the Google customer base.

A badly written SELECT * on an unpartitioned table can still produce a surprising invoice — that is what the partitioning guide is for.

-- BQ: make the expensive mistake fail
create table analytics.events (
  event_id string,
  user_id string,
  event_type string,
  occurred_at timestamp
)
partition by date(occurred_at)
cluster by event_type
options (require_partition_filter = true);

Dry-run every new dashboard SQL. Bytes × runs per month is the number that belongs in the runbook, not a feeling about “BQ being cheap for ad hoc.”

When Snowflake is simpler

  • Multi-cloud, or a credible chance the warehouse is not allowed to live only on GCP.
  • Data sharing with customers who are already on Snowflake (or will be). Secure Data Sharing is still the product to beat for “here is a live table in your account.”
  • Workloads that stay warm: BI caches, frequent incremental dbt, many small queries. You pay to keep a warehouse ready; you save by suspending it. A stream of 200 tiny queries can be cheaper on a sitting Snowflake warehouse than as 200 on-demand BQ scans — or the reverse. Measure.
  • You want Iceberg files in your bucket with warehouse SQL. BQ has BigLake / external tables; the muscle memory and sharing story are not the same.
-- Snowflake: make idle fail
alter warehouse bi_wh set
  auto_suspend = 60
  auto_resume = true
  warehouse_size = 'small';

SQL and features (enough to choose, not a checklist war)

Topic BigQuery Snowflake
Dialect GoogleSQL Snowflake SQL
Semi-structured JSON / STRUCT / JSON_QUERY VARIANT / LATERAL FLATTEN
Incremental transforms Scheduled queries, dbt, Dataform Tasks, dbt, Streams + Tasks
Time travel Time travel / snapshots (confirm edition) Time Travel + Fail-safe — see the Time Travel guide
ML in SQL BQML Cortex, Snowpark ML
Streaming Storage Write API, Pub/Sub Snowpipe, Kafka connectors
Open lake tables BigLake, Iceberg (evolving) Native + managed Iceberg
Sharing Analytics Hub, authorized views Secure Data Sharing, listings

Dialect conversion is a week for a small project and a quarter for a warehouse with 2,000 models. Do not treat “SQL is SQL” as a migration plan. Window frames, QUALIFY, MERGE, scripting, and UDF languages all differ in the corners that break CI.

Reservations vs warehouses

BigQuery editions and slot reservations are how you stop on-demand from being a random walk. You buy capacity. Queries queue or run inside that capacity. This is closer to “we have a warehouse” than people admit — you still size something, you just size slots.

Snowflake multi-cluster is how you stop a Monday dashboard stampede from queueing behind dbt. You still size warehouses, and you split them so transform cannot steal BI.

BQ reservation mistake: buy slots, never partition, burn the
  reservation on full scans, then buy more slots.

SF warehouse mistake: one Large for everything, never suspend,
  then “Snowflake is expensive.”

Same failure mode, different object name.

flowchart TD
  q[Same SELECT] --> bq[BigQuery on-demand]
  q --> sf[Snowflake]
  bq --> scan[Bytes scanned × rate]
  sf --> wh[Warehouse size × time awake]
  scan --> prune[Partition, cluster, name columns]
  wh --> sleep[Auto-suspend, right-size, split BI]

BQ bills what you read. Snowflake bills how long the warehouse stayed up. Tune the invoice you actually have.

Sharing and multi-cloud (the actual deal-breakers)

Already on GCP, consumers are GCP. BigQuery. Authorized views and Analytics Hub cover a lot. You do not need Snowflake for “another team in our org.”

Consumers are Snowflake customers, or you sell data as a listing. Snowflake. Replicating BQ out so a customer can SELECT in their Snowflake account is a product, not a connector you flip.

Two clouds, one warehouse team. Snowflake (or two warehouses and a hard life). BigQuery Omni exists for querying elsewhere; it is not the same as “we run one Snowflake account per cloud and replicate what we must.”

Regulator says the data stays in this cloud / this bucket. Either can work. Snowflake Iceberg and BQ external / BigLake both put files in your storage. Native tables in either platform are a different residency conversation — read the current shared- responsibility docs, do not trust a diagram from a conference.

A practical measurement week

Before you pick (or before you rage-quit the current bill):

If you are on BigQuery today

-- Approximate: jobs that scanned the most (adjust region/project)
select
  user_email,
  destination_table.dataset_id,
  total_bytes_billed,
  query
from `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
where creation_time > timestamp_sub(current_timestamp(), interval 7 day)
  and job_type = 'QUERY'
  and state = 'DONE'
order by total_bytes_billed desc
limit 20;

If you are on Snowflake today

select
  warehouse_name,
  sum(credits_used) as credits
from snowflake.account_usage.warehouse_metering_history
where start_time > dateadd(day, -7, current_timestamp())
group by 1
order by 2 desc;

Then ask: are the expensive things scans we can prune or idle / size we can cut? That answer is the platform argument, not a Twitter thread.

-- Snowflake: full-partition scans. Prune or you are paying warehouse
-- time to read the same fact everyone already paid to store.
select
    query_id,
    warehouse_name,
    partitions_scanned,
    partitions_total,
    bytes_scanned,
    query_text
from snowflake.account_usage.query_history
where start_time > dateadd(day, -7, current_timestamp())
  and partitions_total > 0
  and partitions_scanned = partitions_total
  and execution_status = 'SUCCESS'
order by bytes_scanned desc
limit 20;

Pitfalls

  • Comparing on-demand BQ to a Snowflake warehouse that never sleeps. You are comparing a taxi meter to a rental car you left running.
  • Comparing reserved BQ slots to Snowflake without including the unused slot hours. Capacity you bought and did not use is still spend.
  • Migrating 2,000 models because a new exec “prefers” a logo. Dialect + tests + IAM + sharing is the cost. The logo is the press release.
  • SELECT * in Looker / Tableau explores. On BQ this is a scan event. On Snowflake this is a warehouse event. Both are bad; the invoice line differs.
  • Assuming clustering on BQ equals clustering on Snowflake. Different maintainers, different bills. Read both docs.
  • Using BigQuery as a queue or Snowflake as a document store. Wrong tool, right invoice.
  • Omni / Iceberg / BigLake as a strategy without a writer. External tables do not invent a grain.

Decision rules

  • Already on GCP, SQL-heavy, consumers are GCP → BigQuery unless sharing or multi-cloud forces Snowflake.
  • Multi-cloud, or heavy Snowflake-to-Snowflake sharing → Snowflake unless the team is already fluent in BQ reservations, editions, and slot math.
  • Warm, chatty BI + incremental dbt all day → model both bills for your query mix. Do not guess from a vendor’s “customer saved 40%” slide.
  • Cold, huge, well-partitioned scans a few times a day → on-demand BQ is often the honest fit.
  • You need open files in your bucket and warehouse SQL → either can, but Iceberg-on-Snowflake vs BigLake is an implementation choice after the cloud gravity decision.

If two rules conflict, gravity wins. Moving the warehouse off the cloud that holds the sources is more expensive than living with the second-best billing model.

FAQ

Is a 2-second BigQuery job cheap? If it scanned 40 TB, you billed 40 TB. Runtime is not the invoice.

Will a bigger Snowflake warehouse fix a missing partition filter? It will finish faster and cost more. Fix the prune first; size second.

Do reservations make SELECT * free on BigQuery? No. You burn slots (or on-demand bytes) on columns nobody needed. Name the columns.

Can I compare list price per TB to list price per credit? Not usefully. Use a week of INFORMATION_SCHEMA / ACCOUNT_USAGE and your contract.

When is idle the bigger problem than scans? On Snowflake, a Medium that never suspends. On BigQuery, idle is not the meter — scans are. Do not bring warehouse-idle thinking to an on-demand BQ bill.

What this means for data engineers

Optimize the thing the invoice measures. On BigQuery that is bytes and partitions. On Snowflake that is warehouse time and size. Pick the platform that matches your cloud and your sharing story, then put the dry-run / ACCOUNT_USAGE queries in the Monday review.

The wrong reason to switch is a conference keynote. The right reason is a consumer you cannot serve, or a bill you can explain with SQL and still cannot accept.

Share this post:X / TwitterLinkedIn

Enjoyed this post?

Get the next one in your inbox — one email a week, no spam.

Newsletter signup is not live yet. Use the contact form if you want to be notified.

More on Tools

↑↓ navigate openesc close