Section 1: How BigQuery runs and bills your queries
Why SELECT * is expensive, and LIMIT does not help
Two habits from other databases cost real money in BigQuery.
SELECT * reads every column
SELECT *
FROM `bigquery-public-data.samples.github_timeline`
LIMIT 10;
This query processes the entire table, every column, even though you only see ten rows. In a row oriented database, LIMIT might stop early. In BigQuery, with on demand pricing, LIMIT does not reduce the bytes billed for a plain table scan, because the cost is determined by the columns read across the table.
Select only what you need
SELECT repository_name, type, created_at
FROM `bigquery-public-data.samples.github_timeline`
WHERE type = 'PushEvent';
Selecting three columns can cut the bytes processed dramatically. The WHERE clause on a non partitioned, non clustered column does not reduce bytes scanned, but it still reduces how much data moves through later stages, so the query runs faster.
Preview without paying
To look at sample rows, use the Preview tab on the table in the console, or the bq head command. Both are free because they read stored data directly rather than running a query.
EXCEPT for wide tables
When you need almost every column, exclude the big ones you do not need:
SELECT * EXCEPT (payload, raw_json)
FROM `my_project.events.raw_events`
WHERE event_date = '2026-03-01';
Check before you run
The query validator in the console shows the estimated bytes. From the command line, a dry run returns the same estimate without running anything:
bq query --use_legacy_sql=false --dry_run \
'SELECT repository_name FROM `bigquery-public-data.samples.github_timeline`'
A habit that pays off
Before running any query against a large table, read the estimate and ask whether it matches the question. "How many orders did we have yesterday" should not process a terabyte. When the estimate looks wrong, it usually means the query is missing a partition filter or reading columns it does not need. Both are easy to fix once you look.