What does my hourly BigQuery slot demand look like?
The 30-day hourly profile you need before deciding anything about reservations. Aggregates only — no query text.
Free to run — INFORMATION_SCHEMA scans no billable bytesChecked 4 Aug 2026
JOBS and TABLE_STORAGE are region-scoped.
-- Hourly aggregates only: no query text, no table names, no identities.
-- This is the exact extract the Slot vs On-Demand Advisor consumes.
SELECT
TIMESTAMP_TRUNC(creation_time, HOUR) AS hour,
COUNT(*) AS jobs,
SUM(total_bytes_billed) AS bytes_billed,
SUM(total_slot_ms) AS slot_ms,
APPROX_QUANTILES(
SAFE_DIVIDE(
total_slot_ms,
NULLIF(TIMESTAMP_DIFF(end_time, start_time, MILLISECOND), 0)
), 100
)[OFFSET(95)] AS p95_concurrent_slots_in_hour
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
AND job_type = 'QUERY'
AND statement_type != 'SCRIPT'
AND total_slot_ms IS NOT NULL
GROUP BY hour
ORDER BY hour;What it returns
- slot_ms
- Total slot-milliseconds in the hour. Divide by 3,600,000 for average concurrent slots.
- p95_concurrent_slots_in_hour
- A within-hour peak indicator that hourly averages hide.
How to read it
- Average concurrent slots for an hour = slot_ms ÷ 3,600,000. That is the number a baseline reservation has to cover.
- Hours that ran nothing do not appear in this result — but baseline slots bill through them anyway. Any capacity decision made from this data must refill the missing hours with zeros first, or it will overstate savings badly.
- Thirty days is the minimum useful window: it is the only way to see month-end close and weekly reporting cycles.
Take it further
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.