1 — Start simple
Start simply before adding complexity, especially before applying aggregations like SUM(BilledCost). Ask “what question am I trying to answer?” Apply one filter at a time, look at the results, build understanding.
Gall’s Law: Complex working systems evolve from simple working systems. Complex systems built from scratch don’t work.
2 — Validate results
- Validate over a small time range — restrict to a 1-hour slice you can manually inspect.
- Use
LIMIT— query the first 100 lines, validate, then expand. Also reduces query cost when paying per result size. - Cross-tool validation — if you have FOCUS data in two tools, recreate the report in both. Same number = confidence.
3 — Use appropriate filters
Prefer normalized columns — they work consistently across all data generators.
| Goal | Non-optimal | Optimal |
|---|---|---|
| Find usage charges (excluding credits) | WHERE BilledCost > 0 | WHERE ChargeCategory = 'Usage' |
4 — Use negated filters
When you filter for “all costs related to X,” also run the negated filter to see what you’re excluding. This catches misclassifications and confirms your filter actually makes sense.
FILTER (WHERE ServiceName != 'VirtualMachineService')
5 — Avoid SUBSTRING matching (LIKE)
Substring matching is fragile — results are dynamic. If a charge description changes (which providers do without warning), your filter silently breaks. Use a more specific filter when one is available.
| Non-optimal | Optimal |
|---|---|
WHERE ChargeDescription LIKE 'VM Usage%' | WHERE ServiceName = 'VirtualMachineService' |
6 — Use DISTINCT or GROUP BY
DISTINCT— removes duplicates, returns unique values.GROUP BY— organises into groups; allows aggregation (sum, max, min) within each group.
Prefer GROUP BY when both work — it gives you aggregation flexibility.
7 — Gather feedback
Start every query project with a 15-minute conversation:
- What business question are we answering?
- What decision depends on this answer?
- Which cost metric matters —
BilledCost,EffectiveCost,ListCost,ContractedCost? - What time period and granularity are relevant?
- How will the results be used — dashboard, report, one-time analysis?
Share interim results: “here’s one day, does this align with your expectations?” When presenting, show row counts, explain filters, highlight surprises.
8 — Be mindful of date ranges
- Start dates are inclusive, end dates are exclusive.
- Watch for queries crossing month, year, or short-month (February) boundaries.
- In cloud billing, a month is not a month — date math doesn’t always work the way you expect.
Composing the practices
These don’t live in isolation. A typical query layered them all:
SELECT
ServiceName,
ConsumedUnit,
SUM(BilledCost) / NULLIF(SUM(ConsumedQuantity), 0) AS CostPerUnit,
SUM(ConsumedQuantity) AS TotalQuantity,
COUNT(DISTINCT ResourceId) AS ResourceCount
FROM focus_data
WHERE ChargeCategory = 'Usage'
AND ChargePeriodStart >= '2026-04-01T00:00:00Z'
AND ChargePeriodStart < '2026-05-01T00:00:00Z'
AND BillingCurrency = 'USD'
AND ConsumedQuantity > 0
GROUP BY ServiceName, ConsumedUnit
ORDER BY CostPerUnit DESC
LIMIT 100;
Beyond the eight — supplementary practitioner notes
Allocation
- Tag-only allocation is fragile in reorganising companies. Use external allocation keys keyed off Subscription/Resource Group, Account/OU, or Account/Folder.
- Shared service costs need usage-based allocation. Account-level or label-only allocation often isn’t enough — build allocation from authoritative operational systems (Prometheus, product telemetry).
- Distinguish customer types. Reporting cost-per-user loses meaning when free, paid, and internal users mix.
Unit economics
The recurring lesson: make unit cost visible at general availability, not retroactively. Pick the right unit per industry — per request, per customer, per CI minute, per AI inference, per vehicle, per GB stored.
FinOps for AI
- Decide where AI has business value before scaling spend.
- Compare models on price, performance, privacy, and risk — not price alone.
- Use RAG or targeted customisation when it avoids unnecessary training.
- Monitor AI budgets, usage, forecasts, and carbon impact from day one.
Anti-patterns to avoid
- Letting one expert hold all billing-data understanding.
- Treating cost dashboards as separate from business dashboards.
- Holding teams accountable for cost without giving them data, tools, or decision rights.
- Letting FinOps become a manual reporting factory. Standardisation should shift FinOps from report production to analysis and optimisation.
Knowledge check
Q. Last quarter you wrote a report that pulls all virtual-machine charges using WHERE ChargeDescription LIKE 'VM Usage%'. It worked perfectly until the provider quietly renamed the description text to "Compute Usage" in their April release notes. You don’t notice. What does your April report show, and what should you have done?
ChargeDescription is a vendor-controlled string; providers can rewrite it without notice. Substring/LIKE filters look stable until the day they aren’t, and the failure mode is silent — no error, just wrong numbers. Always prefer normalized columns (ServiceName, ChargeCategory, PricingCategory) for filters that need to survive vendor wording changes.