Q&A library BigQuery

How does BigQuery pricing work, and how do I avoid a surprise bill?

BigQuery Beginner costwarehouse

Short answer

On demand pricing charges for bytes scanned, not rows returned. SELECT star on a wide table can cost a hundred times more than the same query naming three columns.

The short version

BigQuery on demand pricing bills you for the bytes your query reads, not for the rows it returns. LIMIT 10 does not reduce the bill. Naming your columns does, because BigQuery stores data by column and only reads the ones you ask for.

The single most expensive habit

SELECT * FROM `project.dataset.survey_responses` LIMIT 10;

This reads every column of every row in the table. On a survey table with two hundred columns, you have just paid to read two hundred columns to look at ten rows.

SELECT respondent_id, state, enrolled
FROM `project.dataset.survey_responses`
LIMIT 10;

Three columns. Roughly one and a half percent of the bytes.

Know the cost before you run it

The editor shows an estimate before execution. From the command line:

bq query --use_legacy_sql=false --dry_run \
  'SELECT respondent_id, state FROM `project.dataset.survey_responses`'

It reports bytes processed without running the query or charging you.

Partition, so a date filter reads less

A partitioned table stores each day separately. A query filtered on the partition column reads only those days.

CREATE TABLE `project.dataset.monitoring`
PARTITION BY DATE(collected_at)
CLUSTER BY state
AS SELECT * FROM `project.dataset.raw`;

Now this reads one day, not the whole history:

SELECT state, COUNT(*)
FROM `project.dataset.monitoring`
WHERE DATE(collected_at) = '2026-06-01'
GROUP BY state;

Without partitioning, the same query scans everything and charges accordingly.

Set a hard limit before you need one

Custom quotas cap the bytes any query, user or project may process per day. Set them on day one, not after the invoice. A single unbounded query against a large table has cost organisations real money, and it is always somebody exploring rather than somebody malicious.

The trap in a dashboard

A dashboard connected live to BigQuery runs its queries every time somebody opens it. If a page has twelve visuals and forty people open it daily, that is a lot of scans. Two defences: cluster and partition the tables the dashboard hits, and put a materialised view or a scheduled aggregate table between the dashboard and the raw data. The dashboard reads a small summary table; the summary refreshes once.

That is the difference between a live dashboard and an expensive one.

Enjoying these?

Go from piecing together answers to real fluency.

Our courses take you from looking things up to doing the work with confidence, step by step on real data.

Browse the courses