Which days had abnormal GCP spend?
Daily cost against a trailing 7-day mean, flagged by standard deviations.
Costs money to run — queries your billing export tableChecked 4 Aug 2026
WITH daily AS (
SELECT
DATE(usage_start_time) AS usage_date,
service.description AS service,
SUM(cost) AS cost
FROM `PROJECT.DATASET.gcp_billing_export_v1_XXXXXX_XXXXXX_XXXXXX`
WHERE _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 60 DAY)
GROUP BY usage_date, service
),
stats AS (
SELECT
usage_date, service, cost,
AVG(cost) OVER w AS trailing_mean,
STDDEV(cost) OVER w AS trailing_stddev
FROM daily
WINDOW w AS (
PARTITION BY service ORDER BY usage_date
ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING
)
)
SELECT
usage_date, service,
ROUND(cost, 2) AS cost,
ROUND(trailing_mean, 2) AS trailing_mean,
ROUND(SAFE_DIVIDE(cost - trailing_mean, NULLIF(trailing_stddev, 0)), 2) AS z_score
FROM stats
WHERE trailing_stddev > 0
AND SAFE_DIVIDE(cost - trailing_mean, trailing_stddev) > 3
ORDER BY usage_date DESC, z_score DESC;What it returns
- z_score
- Standard deviations above the trailing 7-day mean.
How to read it
- A z-score above 3 on a service with steady spend is worth investigating. On a service that is naturally bursty it is noise — tune the threshold per service or restrict the query to your steady ones.
- The last day or two of the export is usually incomplete and will look like a drop. Exclude the current day.
- This finds spikes, not slow drift. A service growing 4% a week never trips it and will still double in half a year.
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.