BigQuery total_slots_ms 估算成本与账单差异
结论
total_slot_ms × 0.04 美元/slot-hour 得到的是作业实际消耗的 slot 时间所对应的金额,并不是 Standard Edition reservation 的实际账单金额。两者相差很大并不异常。
BigQuery Editions 的容量费用主要取决于计费期间 reservation 实际配置或由 autoscaler 提供的容量,具体包括:
- 持续计费的 baseline slots;
- autoscaling 已提供、但作业没有完全使用的 slots;
- autoscaling 的计费粒度、最短计费时间和缩容延迟;
- 使用该 reservation 的其他项目、文件夹或组织中的作业;
- 区域价格、币种、折扣和 credits。
因此,total_slot_ms 适合衡量计算资源利用率,不能直接作为 reservation 的计费基数。实际金额应以 Cloud Billing 导出数据为准。
为什么 total_slot_ms 会低于账单
total_slot_ms 表示作业执行期间实际消耗的 slot 毫秒数。下面的单位换算没有问题:
slot-hours = total_slot_ms / (1000 × 60 × 60)
但 reservation 采用容量计费。假设某个 reservation 在一小时内有 500 个可计费 slots,而作业实际只使用了其中 100 个:
计费容量:500 slot-hours
作业消耗:100 slot-hours
通过 total_slot_ms 只能算出后者。其余空闲容量不会出现在作业的 total_slot_ms 中,但 baseline capacity 仍可能产生费用。
autoscaling 也不是严格按每个作业消耗的 slot 毫秒数结算。扩出的容量可能在作业结束后继续保留一段时间,并受到最短计费时间和容量调整粒度的影响。即使没有固定 baseline,所有作业的 total_slot_ms 相加,也不一定等于可计费的 slot 时间。
此外,0.04 不能作为所有场景下的固定单价。实际价格取决于 edition、region、购买方式、合同折扣和币种。使用 commitments 时,还要同时计算承诺容量的费用和 credits。
当前查询还有几个统计范围问题
1. 只统计了一个项目
查询使用的是:
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE project_id = 'open-bridge-bg'
一个 reservation 可以供多个项目使用,也可以通过 folder 或 organization assignment 共享。账单包含整个 reservation 的容量成本,而这条查询只能看到一个项目中的作业。
需要确认以下范围是否一致:
- reservation 所在的 location;
- reservation 的所有 assignments;
- 使用该 reservation 的全部项目;
- 查询时间范围和账单周期;
- 账单使用的时区。
如果具备组织级权限,可以考虑使用相应区域的 JOBS_BY_ORGANIZATION。否则,需要分别收集所有相关项目的作业数据。
2. CROSS JOIN UNNEST 会排除空数组作业
下面的写法会直接排除 job_stages 或 timeline 为空的作业:
CROSS JOIN UNNEST(job_stages)
CROSS JOIN UNNEST(timeline)
同时展开两个数组还会产生笛卡尔积。当前的 GROUP BY 在部分情况下可以将结果重新聚合为一行,但这会增加扫描量和计算复杂度,后续修改查询时也容易造成重复统计。
计算总 slot 使用量不需要展开这两个数组。
3. 日期条件可能覆盖 31 个日期
下面的条件包含起止两端:
DATE(creation_time) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
AND CURRENT_DATE()
它通常会覆盖今天和此前 30 个日期,共 31 个日历日期。如果账单按 UTC 或指定的账单时区结算,边界处还可能出现偏差。建议改用半开区间,并明确时区。
4. 脚本父作业可能导致重复统计
多语句查询可能同时产生 SCRIPT 父作业和子作业。按当前统计目的,应只计算子作业,避免把父作业汇总值与子作业再次相加。常见的过滤条件是:
WHERE statement_type != 'SCRIPT'
OR statement_type IS NULL
先正确统计作业消耗
下面的查询用于计算某个项目在指定 UTC 时间范围内实际消耗的 slot。它不会展开 job_stages 和 timeline:
SELECT
reservation_id,
SUM(total_slot_ms) AS consumed_slot_ms,
SAFE_DIVIDE(SUM(total_slot_ms), 1000 * 60 * 60) AS consumed_slot_hours,
SAFE_DIVIDE(SUM(total_slot_ms), 1000 * 60 * 60) * 0.04
AS consumption_value_at_004
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE project_id = 'open-bridge-bg'
AND creation_time >= TIMESTAMP('2026-08-01 00:00:00+00')
AND creation_time < TIMESTAMP('2026-09-01 00:00:00+00')
AND (statement_type != 'SCRIPT' OR statement_type IS NULL)
AND total_slot_ms IS NOT NULL
GROUP BY reservation_id;
这里的 consumption_value_at_004 只能理解为:
假设每个实际消耗的 slot-hour 都按 0.04 美元计价,其对应的资源消耗价值。
它不能用来预测 reservation 账单。
如果只统计某个 reservation,还应添加精确的 reservation_id 条件,以免混入按需计算、其他 reservation 或不同 assignment 下的作业。
根据 reservation 容量估算
更接近账单的估算公式是:
估算费用
≈ baseline slot-hours × 对应 edition 单价
+ autoscaled slot-hours × 对应 edition 单价
其中:
baseline slot-hours
= Σ(baseline slots × 持续时间)
autoscaled slot-hours
= Σ(autoscaler 实际提供的额外 slots × 可计费持续时间)
这里应使用 reservation 时间线或监控指标中的“已配置或已提供容量”,而不是根据作业的 total_slot_ms 反推。可以查询所在区域的 reservation timeline 视图,先查看容量变化:
SELECT *
FROM `region-us`.INFORMATION_SCHEMA.RESERVATIONS_TIMELINE
WHERE period_start >= TIMESTAMP('2026-08-01 00:00:00+00')
AND period_start < TIMESTAMP('2026-09-01 00:00:00+00')
ORDER BY period_start;
该视图的具体字段和可见范围,应以当前项目返回的 schema 为准。计算时需要分别处理 baseline、autoscaling 上限和 autoscaler 实际提供的容量,不能把 autoscaling 上限直接视为实际计费容量。
根据相邻时间点计算持续时间时,还要处理以下情况:
- 查询区间开始前已经生效的容量;
- 区间结束时仍然生效的最后一条记录;
- reservation 配置变更;
- autoscaling 的计费规则;
- 不同 edition 或 location 的单价变化。
这种方法可以用于分析容量利用率和估算预算,但不能作为账单对账的唯一依据。
使用 Billing Export 核对实际费用
最可靠的做法是启用 Cloud Billing 导出到 BigQuery,再按 BigQuery SKU 汇总费用和 credits。例如:
SELECT
service.description AS service_description,
sku.description AS sku_description,
currency,
SUM(cost) AS gross_cost,
SUM((
SELECT COALESCE(SUM(credit.amount), 0)
FROM UNNEST(credits) AS credit
)) AS credits,
SUM(cost) +
SUM((
SELECT COALESCE(SUM(credit.amount), 0)
FROM UNNEST(credits) AS credit
)) AS net_cost
FROM `billing_project.billing_dataset.gcp_billing_export_v1_BILLING_ACCOUNT_ID`
WHERE service.description = 'BigQuery'
AND usage_start_time >= TIMESTAMP('2026-08-01 00:00:00+00')
AND usage_start_time < TIMESTAMP('2026-09-01 00:00:00+00')
GROUP BY
service_description,
sku_description,
currency
ORDER BY ABS(net_cost) DESC;
不要一开始就使用模糊的 SKU 名称过滤。先列出 sku.description,确认哪些记录对应:
- BigQuery Standard Edition capacity;
- commitments 或相关 credits;
- analysis、storage、BI Engine、data transfer 等其他费用。
实际导出表名、可用字段和资源标签,取决于启用的是标准导出还是详细导出。
推荐的对账方式
先从 Billing Export 中取得同一账期内 reservation 相关 SKU 的净费用,再根据 reservation timeline 计算同期的可计费容量,最后通过作业的 total_slot_ms 计算利用率:
容量利用率
= 作业实际消耗的 slot-hours
/ reservation 可计费或已提供的 slot-hours
这两类数据回答的是不同问题:
total_slot_ms表示作业实际使用了多少计算资源;- Billing Export 表示这些 reservation 容量实际产生了多少费用。
如果两者差距很大,应优先检查 baseline slots 是否长期空闲、autoscaling 是否利用不足、是否遗漏了其他项目、账期边界是否一致,以及折扣或 credits 是否已计入,而不是用 storage cost 补齐差额。
备注:内容仅供参考。
