Estimate what a query costs before you run it
This recipe tells you what already happened. The analyzer takes a query you have not run yet and estimates what it will scan, in your browser.
Are my BigQuery queries queueing for slots?
Per-hour slot consumption from JOBS_TIMELINE, which shows concurrency the job table cannot.
Reads metadata only, a fraction of a cent to run (10 MB minimum)Reviewed against Google’s docs, 23 Oct 2026
Permissions. Needs bigquery.jobs.listAll on the project for JOBS_TIMELINE (BigQuery Resource Viewer has it); bigquery.jobs.create to run any query (BigQuery Job User has it).
Pick the region your data is in: every INFORMATION_SCHEMA view here is qualified by region.
-- JOBS_TIMELINE reports slot usage per second-level period, so it shows
-- true concurrency rather than a per-job total smeared over its runtime.
-- A script's parent job repeats its children's slot use, so it is left out.
-- The view is partitioned by job_creation_time, not period_start: the
-- job_creation_time filter is what keeps this from reading 180 days.
SELECT
TIMESTAMP_TRUNC(period_start, HOUR) AS hour,
COUNT(DISTINCT job_id) AS concurrent_jobs,
ROUND(SUM(period_slot_ms) / 1000 / 3600, 2) AS slot_hours,
ROUND(SUM(period_slot_ms) / 3600000, 1) AS avg_slots_in_hour,
MAX(period_slot_ms) AS peak_period_slot_ms
FROM `region-us`.INFORMATION_SCHEMA.JOBS_TIMELINE_BY_PROJECT
WHERE period_start >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
AND job_creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 8 DAY)
AND job_type = 'QUERY'
AND (statement_type != 'SCRIPT' OR statement_type IS NULL)
GROUP BY hour
ORDER BY avg_slots_in_hour DESC
LIMIT 100;What it returns
- avg_slots_in_hour
- Average slots in use across the hour.
- concurrent_jobs
- Distinct jobs active at some point in the hour.
- peak_period_slot_ms
- The most slot-milliseconds one job used in one second of the hour. Divide by 1,000 for that job's slots; it is not the hour's total concurrency.
How to read it
- On-demand projects draw from a finite, best-effort pool. If your busiest hours sit near a flat ceiling, you are already being throttled and your measured demand understates what you would actually use.
- Busy hours that all sit at the same value in the result are the signature of contention. Genuine demand is spiky; ceilings are flat.
- JOBS_TIMELINE is much larger than JOBS. Keep the window short or the metadata query itself gets slow and reads more bytes, which on demand are billed like any query. The job_creation_time filter is what limits the read: the view is partitioned on it. It starts a day before the window so a job created just before it still counts.
Run this once, or have it run every day.
Finitizer evaluates this class of question continuously against your live BigQuery estate, tracks how each number moves between runs, and turns findings into assigned tasks. Read-only and keyless.
See how Finitizer works