Building the Chargeback Dashboard
Estimated read: 3 min
A chargeback taxonomy that only lives in queries someone runs manually each month doesn’t change
behavior – it just produces a monthly argument. The fix is the same one you’d have reached for on
top of a Teradata resource-usage table: a self-serve dashboard that any team lead can open, filter
to their own tag, and trust without asking the platform team to run a query for them. In Databricks
SQL, that’s a dashboard built directly on top of the system.billing.usage / list_prices join
from the first lecture, with a scheduled refresh so the numbers are never more than a day stale.
The dashboard needs exactly three panels to answer the questions Finance and team leads actually ask, each driven by one shared date-range filter so every panel stays in sync:
Panel 1 – Headline spend. A single counter showing total list-cost dollars for the selected period, with a small trendline against the prior period. This is the number that opens the monthly FinOps review.
SELECT SUM(u.usage_quantity * p.pricing.default) AS total_spend_usd
FROM system.billing.usage u
JOIN system.billing.list_prices p
ON u.sku_name = p.sku_name AND u.cloud = p.cloud
AND u.usage_start_time >= p.price_start_time
AND (u.usage_start_time < p.price_end_time OR p.price_end_time IS NULL)
WHERE u.usage_date BETWEEN :start_date AND :end_date
Panel 2 – Spend by team. A bar chart grouping the same join by the team key inside
custom_tags, sorted descending, with an explicit “Untagged” bucket rather than silently dropping
rows with no tag – an unattributed slice that grows month over month is itself a signal that tag
enforcement is slipping.
SELECT
COALESCE(u.custom_tags['team'], 'Untagged') AS team,
SUM(u.usage_quantity * p.pricing.default) AS spend_usd
FROM system.billing.usage u
JOIN system.billing.list_prices p ON /* same join as above */ TRUE
WHERE u.usage_date BETWEEN :start_date AND :end_date
GROUP BY 1
ORDER BY 2 DESC
Panel 3 – Team-project drill-down. A table, wired to Databricks SQL’s native drill-down/filter
interaction, that lets a viewer click a bar in Panel 2 and see that team’s spend broken out by the
project tag underneath it – the level of detail a team lead needs to answer “which of my
pipelines is actually driving this.”
All three panels share the single :start_date/:end_date date-range parameter as a dashboard-level
filter, so changing the range once updates the headline number, the team breakdown, and the
drill-down together – the self-serve property that turns this from a report into a tool. Schedule
the dashboard’s underlying queries to refresh daily (Databricks SQL’s dashboard refresh schedules
handle this natively, with no external orchestration needed), and grant CAN VIEW broadly across the
organization while keeping the underlying system.billing schema itself locked down to the FinOps
role – the dashboard is the sanctioned window into that data, not a bypass of its access control.
Two design choices separate a dashboard people actually open from one that gets built once and
forgotten. First, add a month-over-month delta next to the headline number, not just an absolute
figure – “$142K, up 8% vs. last month” prompts a conversation in a way “$142K” alone doesn’t.
Second, resist the temptation to add a tenth panel for every possible cut of the data; a chargeback
dashboard’s job is to answer the three questions above fast, and a team lead who needs a deeper cut
should drop into the underlying system.billing.usage table directly with the query pack from later
in this section, not hunt through a cluttered dashboard for a panel someone added for a one-off
request. Keep the dashboard as the fast path, and the raw tables as the escape hatch for everything
else – the same division of labor a legacy BI team drew between a canned executive report and the
ad hoc query tool underneath it.
| ← Previous: Attribution and Chargeback Taxonomy | Next: Predictive Optimization: Proving Savings, Not Just Space → | |:—|—:|