Dashboard

What goes in a BigQuery monitoring dashboard in Metabase?

A BigQuery monitoring dashboard tracks job volume, execution time, bytes scanned versus billed, slot utilization, and spend by project — and names the queries responsible. Metabase connects to BigQuery natively, so every card is plain SQL over INFORMATION_SCHEMA.JOBS — no exporter or agent in between.

For: data platform teams, analytics engineers, and whoever owns the warehouse bill. Grain: one row per job, rolled up daily. Source: INFORMATION_SCHEMA.JOBS_BY_PROJECT (≈180-day retention — snapshot nightly for more).

What does a BigQuery monitoring dashboard look like?

Here’s the layout this guide builds. Warehouse-level numbers and the month’s spend sit at the top; query volume, performance, errors, and cache behaviour fill the middle; the bottom section follows the money — bytes, slots, and the specific queries that dominate the bill.

BigQuery monitoring dashboard in Metabase showing jobs, execution time, bytes scanned vs. billed, slot utilization, and top queries by cost.

An example BigQuery monitoring dashboard in Metabase, built from INFORMATION_SCHEMA.JOBS. Figures are illustrative.

Which cards belong on a BigQuery monitoring dashboard?

Eight cards, updated from the classic list: percentiles instead of averages for execution time, and bytes billed — the number that costs money — beside bytes scanned.

  • Jobs — volume per hour, plus queries in flight right now (area + number)
  • Query execution time — p50 and p95 by day (line)
  • Bytes scanned vs. bytes billed per day (bar)
  • Slot utilization against the reservation (line)
  • Bytes billed by project, month to date (row)
  • Cache hit rate by day (line)
  • Failed jobs by error type — rate limits, invalid queries, timeouts (stacked bar)
  • Top queries by bytes billed, with estimated cost (table)

What data does the dashboard need?

  • INFORMATION_SCHEMA.JOBS_BY_PROJECT (or JOBS_BY_ORGANIZATION) — job state, timings, total_bytes_processed, total_bytes_billed, cache_hit, total_slot_ms, error_result, user, and query text.
  • A nightly rollup table snapshotting the view — both for history beyond ~180 days and so dashboard refreshes don’t re-scan the raw view.
  • RESERVATION capacity (from the reservations views or config) for the slot-utilization goal line.
  • Optional billing export via Google Cloud billing to reconcile estimated cost against the invoice.

How do you build it?

  1. Connect BigQuery to Metabase with a service account that can read the region-qualified INFORMATION_SCHEMA views.
  2. Schedule a nightly query that appends yesterday’s jobs to a rollup table — always filtered on creation_time, the column the views are partitioned by.
  3. Model the rollup once (est. cost = TB billed × your on-demand rate) and point every card at the model, so cost math never varies by chart.
  4. Build the bytes and top-queries cards first — they pay for the dashboard — then performance, errors, and slots.
  5. Add filters for project, user, and date range, and pin the top-queries table where the data team will actually see it.

Example card SQL

Jobs, p95 execution, bytes, cost, and cache hits by day PostgreSQL
SELECT
DATE(creation_time)                                   AS day,
COUNT(*)                                              AS jobs,
COUNTIF(state = 'RUNNING')                            AS in_flight,
APPROX_QUANTILES(
  TIMESTAMP_DIFF(end_time, start_time, SECOND), 100
)[OFFSET(95)]                                         AS execution_p95_s,
ROUND(SUM(total_bytes_processed) / POW(1024, 4), 2)   AS tb_scanned,
ROUND(SUM(total_bytes_billed) / POW(1024, 4), 2)      AS tb_billed,
ROUND(SUM(total_bytes_billed) / POW(1024, 4) * 6.25, 0) AS est_cost_usd,
ROUND(100 * COUNTIF(cache_hit) / COUNT(*), 1)         AS cache_hit_pct
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 14 DAY)
AND job_type = 'QUERY'
GROUP BY 1
ORDER BY 1;

Metrics

Integrations

Dashboards

FAQ

What is a BigQuery monitoring dashboard?
A BigQuery monitoring dashboard tracks what your warehouse is doing and what it costs — job volume, execution time, bytes scanned and billed, slot utilization, and the specific queries responsible — in one place. Because Metabase connects to BigQuery natively, the whole thing is built from INFORMATION_SCHEMA.JOBS with ordinary SQL: no exporter, no pipeline, no third-party agent.
Where does the data come from?
The INFORMATION_SCHEMA.JOBS views — JOBS_BY_PROJECT for one project, JOBS_BY_ORGANIZATION for everything (requires an org-level role). Each row is one job: state, start and end time, bytes processed and billed, cache hit, slot-milliseconds, error result, user, and the query text. Two practical notes: the views are region-qualified (`region-us`.INFORMATION_SCHEMA…), so query the region your datasets live in, and they retain roughly 180 days — schedule a nightly append into your own table if you want more history.
Why are bytes billed higher than bytes scanned?
On-demand pricing bills a 10 MB minimum per table referenced, rounds up, and charges some operations that scan little. So total_bytes_billedtotal_bytes_processed, and lots of small queries against many tables can bill noticeably more than they scan — visible as the persistent gap between the two bars in the example. Chart both: scanned tells you about query behaviour, billed is the one that costs money.
How do I find the queries that cost the most?
Rank by SUM(total_bytes_billed) over the month, grouping by the normalized query text or by referenced table. It is normal for a handful of scheduled queries to dominate — in the example, five full scans of an unpartitioned events table account for 61% of month-to-date bytes billed. That table is the to-do list: partitioning, clustering, or materializing the hot subset usually cuts the top offenders by an order of magnitude.
On-demand or capacity (slot) pricing — and what changes here?
On-demand bills per TB scanned, so the bytes-billed cards are your cost cards. Capacity pricing bills for slot reservations, so cost shifts to the slot-utilization card: a reservation pinned at its ceiling during business hours means queued queries and rising p95s, while one idling at 30% is money to reclaim. Most orgs on reservations keep both sets of cards — bytes for efficiency, slots for capacity — plus baseline billing export via Google Cloud billing.
Does the monitoring itself cost money?
Very little, if you aggregate. INFORMATION_SCHEMA.JOBS queries bill for the bytes they process like any other query, but the views are small relative to real workloads, and daily rollups touched once a night cost cents. Two habits keep it that way: filter on creation_time (the views are partitioned by it), and point dashboard cards at a nightly rollup table rather than re-scanning the raw view on every refresh — Metabase's own result cache helps too.
How is this different from a cloud spend dashboard?
Scope. A cloud spend overview reads billing exports across services and answers "what did we spend, where, versus budget". This dashboard reads the workload itself and answers "which queries, tables, and schedules cause the BigQuery line item, and is the warehouse healthy". They meet in the middle: the spend dashboard flags BigQuery as the anomaly, this one names the query responsible — see cost anomalies for the alerting side.