A different dialect

The archive's meter: you pay for the bytes read

10 min
O que você vai aprender
  • to price a query before you run it: the "you pay for the bytes read" model
  • to explain why SELECT * is money down the drain, while LIMIT does not shrink the bill
  • to use the dry run and the results cache
  • to understand when slots pay off for a company instead of paying per byte

The morning invoice

The morning starts with a call: the station commandant has forwarded you a statement. For yesterday's queries to the Far Archive the meter drew a noticeable chunk of the donor station's energy — and next to every query there is a number.

You look through the list and notice something strange: the most "expensive" query returned five rows. The cheapest returned fifty. The price is clearly not about how many rows came back.

QUERY: I went through the archive's price list while you slept. Bad news: what you pay for here is reading, not the answer. Good news: that means the price is something you can steer.

The station meter: two full columns of data drain wholesale into the gauge while only a few drops of result fall into the cup below. The cadet stands before it holding a ledger of light; the robot cat watches the level drop.
You pay for whole columns read, not for the rows returned: LIMIT shrinks the output, never the bill.

The on-demand model: bytes, not rows

In its basic mode (on-demand) BigQuery charges for one thing: how many bytes of tables the query read. In Earth money that is about $6.25 per TiB read (the first TiB each month is free). A TiB is a tebibyte, a binary terabyte: 1024 GiB ≈ 1.1 of an "ordinary" TB. Google's price list counts in exactly those, so the course does too. The station's meter works the same way, only the currency is different.

Recall the previous lesson: data lies in columns. So the volume read is counted simply:

scan = the sum of the sizes of the columns read, each one whole

  • SELECT name FROM fa_users — one column, name, is read across every row of the table;
  • SELECT * FROM fa_users — EVERY column is read;
  • the number of rows in the answer does not affect the bill at all.

In Postgres you never thought about the "cost" of a SELECT: your server, your disk, and the difference between a fast query and a slow one is minutes of waiting. In BigQuery every query has a price in money — and it is known BEFORE you run it.

Why LIMIT does not save money

A habit from the row world: "I will add LIMIT 10 — less work for the database". In a row store that is close to the truth: read ten rows from the start, then stop.

A columnar engine works differently: to hand you even a single row it has already read the columns it needs whole — distributed, in large blocks. LIMIT is applied at the very end, to the finished result. By that moment the bill has already been issued.

The same goes for WHERE (as long as the table is not partitioned — that is the chapter "Money and scale"): the filter cuts the number of rows in the answer, but the columns from WHERE and SELECT were still read across the whole table.

Let us do the arithmetic. Imagine the colony's event log has grown to size: ten columns of roughly equal weight, 5 TiB in total — about 500 GiB per column. Then:

-- reads ~1 TiB (two whole columns): ~$6.25
SELECT user_id, event_name FROM journal;

-- reads EXACTLY the same: ~$6.25
SELECT user_id, event_name FROM journal LIMIT 100;

-- reads all 5 TiB: ~$31
SELECT * FROM journal LIMIT 100;

One SELECT * "just to look" is like leaving the tap open: the water has already run out, however many glasses you pour.

The bill is counted before LIMIT, not afterSELECT * … LIMIT 10read5 TiB10 rowsSELECT user_id, tsread1 TiB10 rowsyou pay for columns read, not for rows returned
Both queries return ten rows — but you pay for the columns that were read

Dry run: the price before the launch. Cache: a repeat is free

The main survival tool is the dry run: a pass over the query without executing it. BigQuery parses the query, looks at the tables' and returns the exact size of the future scan — free and instantly. In the BigQuery console the estimate appears as you type ("This query will process 1.2 TB when run"), in the CLI it is bq query --dry_run, in the API the dryRun flag.

The Postgres habit of EXPLAIN turns into the habit of a dry run here: there you read the plan to save minutes — here you read the bytes to save money.

The second friend is the results cache. Repeat exactly the same query while the data has not changed, and BigQuery hands back the stored result for free (the cache lives about a day). So "run it once more to look" is nothing to fear; what is frightening is "tweak it a little and sweep the whole table again". What exactly breaks the cache (non-deterministic functions such as CURRENT_TIMESTAMP(), for instance) — we will unpick that in the chapter "Money and scale".

Dry run: the bill before you runquery text1.4 TiB will be readno data is read, no money is spent✓ a narrow column list drops the bill at once✗ EXPLAIN here is about bytes, not about time
A dry run shows the volume before you pay for it

Slots: when counting bytes gets old

The "per byte" model has a ceiling: once the queries become very many, a company moves to the capacity model — it buys slots, units of compute power, and pays for them at a fixed rate however many bytes the queries read. Companies switch when the load has become constant, or when knowing the spending ceiling in advance matters more than pricing every single query. That is an administrator's choice, not an analyst's: the billing changes, the syntax does not.

For you the rule is simple: while the bill is counted in bytes, every extra column costs money; if the company runs on slots, a wasteful query still takes shared power away from your colleagues. Cheap habits pay off under both models.

The course sandbox is free — hence an honest warning: the emulator does not count bytes and cannot do a dry run. The numbers in this lesson are arithmetic against the price list of the real BigQuery. In , build the reflex: dry run first, then launch.

Check yourself
The colony's production log: 10 columns of roughly equal weight, 5 TiB for the whole table. How much will the query SELECT user_id, event_name FROM journal LIMIT 100 read, and what is the bill at $6.25/TiB?
Check yourself
The bill for a query against a large unpartitioned table came out far too high. Which edit will REALLY cut the next bill?
Practice: solve the tasks
Solved 0 of 3 · any 2 is enough to pass
Principais pontos
  • on-demand: you pay for the column bytes read, ~$6.25 per TiB; the rows in the answer have nothing to do with it
  • LIMIT and WHERE (without partitions) do not shrink the bill: the columns are read whole before them
  • a dry run shows the exact price before the launch; an exact repeat of a query is served from the cache for free
  • slots are the capacity model for large teams; cheap habits are needed under both

A Postgres habit → a BigQuery idiom (part 1):

Habit from PostgresHow it goes in BigQuery
SELECT * "to glance at the data"a list of columns or SELECT * EXCEPT(...)
LIMIT 10 "to make it cheap"LIMIT is only about the size of the output; it does not change the price
EXPLAIN before a heavy querya dry run: the exact bytes before the launch
CREATE INDEXthere are no indexes: partitioning and clustering (chapter 5)
"the database will cache it itself"the results cache: an exact repeat is free

Documentation: BigQuery pricing, cost best practices.

The meter is understood. But the archive holds data written down in a hurry by dying colonies — it is full of garbage, and a query is not allowed to die. The next lesson is SAFE mode.