GCP BigQuery Cheat Sheet
SQL syntax and CLI/Python client reference for querying, loading, and managing data warehouses in Google BigQuery.
Basic Query
Standard SQL query against a public dataset.
SELECT name, COUNT(*) AS totalFROM `bigquery-public-data.usa_names.usa_1910_2013`WHERE state = 'CA'GROUP BY nameORDER BY total DESCLIMIT 10;
bq CLI Commands
Load data and run queries from the command line.
bq mk my_dataset # Create datasetbq load --source_format=CSV \ my_dataset.my_table gs://my-bucket/data.csv \ name:STRING,age:INTEGERbq query --use_legacy_sql=false \ 'SELECT COUNT(*) FROM my_dataset.my_table'bq show my_dataset.my_table # Table schema/infobq rm -t my_dataset.my_table # Delete table
Python Client
Run a query using the google-cloud-bigquery library.
from google.cloud import bigqueryclient = bigquery.Client()query = """ SELECT name, total FROM `my_dataset.my_table` ORDER BY total DESC LIMIT 10"""for row in client.query(query).result(): print(row.name, row.total)
Key Concepts
Key key concepts to know.
- Dataset- Top-level container for tables and views within a project
- Partitioned Table- Physically divided by a column (often date) to reduce bytes scanned
- Clustered Table- Sorted by column(s) to speed up filtering within partitions
- Slot- Unit of computational capacity used to execute queries
- Materialized View- Precomputed query results automatically refreshed for faster reads
Pricing & Performance Tips
Key pricing & performance tips to know.
- On-Demand Pricing- Billed per TB of data scanned by the query
- SELECT *- Avoid it; BigQuery is columnar and scans only referenced columns, so selecting fewer columns cuts cost
- --dry_run- bq CLI flag to estimate bytes scanned before running a query
- Partition Pruning- Filtering on the partition column skips scanning irrelevant partitions
Creating a Partitioned & Clustered Table
DDL for a table partitioned by day and clustered for a common filter/group-by column.
CREATE TABLE my_dataset.events ( event_id STRING, user_id STRING, event_type STRING, event_ts TIMESTAMP)PARTITION BY DATE(event_ts)CLUSTER BY user_id, event_typeOPTIONS ( partition_expiration_days = 90, require_partition_filter = true);
Analytic (Window) Functions
Compute running totals and rank rows within partitions without collapsing them.
SELECT user_id, event_ts, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_ts) AS event_seq, SUM(1) OVER ( PARTITION BY user_id ORDER BY event_ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS running_event_countFROM `my_dataset.events`QUALIFY event_seq <= 10;
BigQuery Scripting & JS UDF
Multi-statement scripts with variables plus a JavaScript user-defined function.
CREATE TEMP FUNCTION normalize(s STRING)RETURNS STRINGLANGUAGE js AS """ return s.trim().toLowerCase().replace(/[^a-z0-9]/g, '_');""";DECLARE threshold INT64 DEFAULT 100;IF (SELECT COUNT(*) FROM my_dataset.events) > threshold THEN SELECT normalize(event_type) AS clean_type, COUNT(*) AS n FROM my_dataset.events GROUP BY clean_type ORDER BY n DESC;END IF;
Incremental Load with MERGE
Upsert pattern typically wired into a Scheduled Query for nightly incremental loads.
MERGE INTO my_dataset.users_dim TUSING my_dataset.users_staging SON T.user_id = S.user_idWHEN MATCHED AND T.updated_at < S.updated_at THEN UPDATE SET name = S.name, email = S.email, updated_at = S.updated_atWHEN NOT MATCHED THEN INSERT (user_id, name, email, updated_at) VALUES (S.user_id, S.name, S.email, S.updated_at);
Advanced Cost & Governance Controls
Mechanisms beyond partition pruning for controlling spend and access at scale.
- Reservations & Slots- Flat-rate/edition-based capacity purchased in advance (BigQuery Editions) to avoid unpredictable on-demand billing
- Custom Cost Controls- Per-project or per-user maximumBytesBilled query option and daily/query-level quota caps
- Authorized Views- Share query results from a view without granting the underlying table's dataset access
- Row-Level Security- CREATE ROW ACCESS POLICY restricts which rows a principal can see within a shared table
- Column-Level Security- Policy tags in Data Catalog restrict access to sensitive columns independent of table-level IAM
- INFORMATION_SCHEMA.JOBS- Query historical job metadata (bytes billed, slot-ms, cache hits) to audit and optimize spend
Always filter on the partitioning column (e.g. WHERE _PARTITIONDATE or a date column) in WHERE clauses — it lets BigQuery prune unscanned partitions, which directly reduces both query cost and latency.