Skip to main content

Free resource

Cloud unit economics from FOCUS data: cost per 1,000 orders in SQL

How to turn a FOCUS billing export into a cost-per-order number you can defend: choosing the numerator, allocating shared and unused commitment cost, picking the grain, and checking whether cost really scales with volume. Runnable DuckDB SQL on a free synthetic dataset.

By Adam Morad · Reviewed October 1, 2026 · SQL dialect: DuckDB (run on v1.5.3) · FOCUS 1.2 column names · synthetic data

Key points

  • ✓Cost per order is a choice of numerator, denominator and grain; for the same month, September, the answer ranged from $10.86 to $44.61 per 1,000 orders depending on which costs were included. Details
  • ✓Use EffectiveCost, not BilledCost: with an upfront Savings Plan, BilledCost understated September by more than half ($4.86 vs $10.86 per 1,000 orders). Details
  • ✓Charge unused commitment back to the workload it was bought for, or a downsizing looks like a saving it is not ($10.86 vs $12.37 per 1,000 orders). Details
  • ✓Over rolling windows, divide summed cost by summed orders; averaging daily ratios weights quiet days like busy ones. Details
  • ✓Check whether cost moves with volume before celebrating a falling unit cost: here orders grew 26.5% while cost stayed flat, so the drop was a volume effect. Details

Run it yourself (no email needed)

Download the free FOCUS exercise dataset, unzip it, put the SQL file in the same folder and run duckdb < unit-economics.sql. The data is synthetic: a fictional company, Northwind Analytics, with three months of AWS, Azure and Google Cloud billing in FOCUS columns and a daily orders file.

Why cost per order is harder than one division

A unit cost is cloud cost divided by a business volume: orders, customers, API calls. FOCUS makes the cost side consistent across providers, but it cannot decide which costs belong to an order, how to treat shared platform spend, or what to do with commitment cost nobody used. Those are choices, and each one moves the number. The sections below change one choice at a time on the same data.

Setup · views over the CSVs, with a cost classification
CREATE OR REPLACE VIEW focus AS
SELECT *,
       json_extract_string(Tags, '$.team') AS team,
       json_extract_string(Tags, '$.env')  AS env,
       CAST(ChargePeriodStart AS DATE)     AS day
FROM read_csv_auto('focus_exercise_2026-q3.csv');

CREATE OR REPLACE VIEW orders AS
SELECT CAST(date AS DATE) AS day, orders
FROM read_csv_auto('northwind_orders_2026-q3.csv');

-- Which teams serve orders? This mapping is a business decision, not something FOCUS knows.
-- Customer-facing: the services an order actually passes through.
-- Shared: platform costs every team uses (including the Savings Plan's Unused rows).
-- Internal: analytics, data engineering and ML work that does not scale with orders.
CREATE OR REPLACE VIEW cost_classes AS
SELECT *,
       CASE
         WHEN team IN ('checkout', 'search', 'web') THEN 'customer_facing'
         WHEN team = 'platform'                     THEN 'shared'
         WHEN team IS NULL                          THEN 'untagged'
         ELSE 'internal'
       END AS cost_class
FROM focus;

The cost_classes view is the most important line in the file. Which teams serve orders is a business decision you make once and write down; FOCUS only gives you the tags to apply it.

1. The numerator decides the answer

U1 · DuckDB
-- U1. The numerator decides the answer. Same quarter, same orders, four defensible numbers.
--     All on EffectiveCost (amortized), never BilledCost.
WITH monthly_cost AS (
  SELECT date_trunc('month', day) AS month,
         SUM(EffectiveCost)                                                            AS everything,
         SUM(EffectiveCost) FILTER (WHERE ChargeCategory = 'Usage')                    AS usage_only,
         SUM(EffectiveCost) FILTER (WHERE ChargeCategory = 'Usage' AND env = 'prod')   AS prod_usage,
         SUM(EffectiveCost) FILTER (WHERE cost_class = 'customer_facing' AND env = 'prod') AS customer_facing_prod
  FROM cost_classes
  GROUP BY 1
),
monthly_orders AS (
  SELECT date_trunc('month', day) AS month, SUM(orders) AS orders FROM orders GROUP BY 1
)
SELECT strftime(c.month, '%Y-%m')                               AS month,
       o.orders,
       ROUND(c.everything           / o.orders * 1000, 2) AS all_cost_per_1k,
       ROUND(c.usage_only           / o.orders * 1000, 2) AS usage_per_1k,
       ROUND(c.prod_usage           / o.orders * 1000, 2) AS prod_usage_per_1k,
       ROUND(c.customer_facing_prod / o.orders * 1000, 2) AS customer_facing_per_1k
FROM monthly_cost c JOIN monthly_orders o USING (month)
ORDER BY 1;
MonthOrdersAll cost / 1kUsage / 1kProd usage / 1kCustomer-facing / 1k
2026-071,397,01854.8445.8444.2216.38
2026-081,561,36141.1640.8239.3313.01
2026-091,637,01444.6142.6141.2010.86

Same quarter, same orders, four defensible numbers. “All cost” includes tax on the upfront commitment and a one-off credit, which is why July is inflated. “Customer-facing” keeps only the production services an order passes through, and drops analytics and ML work that would cost the same with no orders at all. Pick one definition, label it, and keep it stable; a unit cost that changes definition is worse than none.

2. Allocate shared platform cost instead of dropping it

U2 · DuckDB
-- U2. Allocate shared platform cost instead of dropping it. Platform spend is split across
--     teams in proportion to each team's own prod usage that month (one common rule; others
--     are defensible). The customer-facing share is then added to the numerator.
WITH team_month AS (
  SELECT date_trunc('month', day) AS month, cost_class, SUM(EffectiveCost) AS cost
  FROM cost_classes
  WHERE ChargeCategory = 'Usage' AND (env = 'prod' OR cost_class = 'shared')
  GROUP BY 1, 2
),
pivoted AS (
  SELECT month,
         SUM(cost) FILTER (WHERE cost_class = 'customer_facing') AS customer_facing,
         SUM(cost) FILTER (WHERE cost_class = 'internal')        AS internal,
         SUM(cost) FILTER (WHERE cost_class = 'shared')          AS shared
  FROM team_month GROUP BY 1
),
monthly_orders AS (
  SELECT date_trunc('month', day) AS month, SUM(orders) AS orders FROM orders GROUP BY 1
)
SELECT strftime(p.month, '%Y-%m') AS month,
       ROUND(p.customer_facing, 2) AS customer_facing,
       ROUND(p.shared, 2) AS shared_platform,
       ROUND(p.customer_facing / (p.customer_facing + p.internal), 3) AS customer_facing_share,
       ROUND(p.customer_facing / o.orders * 1000, 2) AS direct_per_1k,
       ROUND((p.customer_facing + p.shared * p.customer_facing / (p.customer_facing + p.internal))
             / o.orders * 1000, 2) AS with_platform_share_per_1k
FROM pivoted p JOIN monthly_orders o USING (month)
ORDER BY 1;
MonthCustomer-facingShared platformCustomer shareDirect / 1kWith platform share / 1k
2026-0722,880.942,137.640.37616.3816.95
2026-0820,308.023,628.700.34413.0113.81
2026-0917,771.164,669.270.27810.8611.65

Splitting platform cost in proportion to each group’s own usage is a common rule, not the only one. Notice the shared platform line more than doubles from July to September. That growth is not new platform work, which is the next section.

3. Charge unused commitment back, or a downsizing looks like a saving

U2b · DuckDB
-- U2b. Where did the "savings" go? After the checkout fleet was downsized on 2026-08-15, part
--      of its Savings Plan went unused. FOCUS records that as Usage rows with
--      CommitmentDiscountStatus = 'Unused', tagged to the platform team that owns the plan,
--      so checkout looks cheaper while the idle commitment lands in "shared". Charging the
--      Unused cost back to the workload the commitment was bought for gives the honest number.
WITH monthly AS (
  SELECT date_trunc('month', day) AS month,
         SUM(EffectiveCost) FILTER (WHERE cost_class = 'customer_facing' AND env = 'prod') AS customer_facing,
         SUM(EffectiveCost) FILTER (WHERE CommitmentDiscountStatus = 'Unused')            AS unused_commitment
  FROM cost_classes
  WHERE ChargeCategory = 'Usage'
  GROUP BY 1
),
monthly_orders AS (
  SELECT date_trunc('month', day) AS month, SUM(orders) AS orders FROM orders GROUP BY 1
)
SELECT strftime(m.month, '%Y-%m') AS month,
       ROUND(COALESCE(m.unused_commitment, 0), 2) AS unused_commitment,
       ROUND(m.customer_facing / o.orders * 1000, 2) AS direct_per_1k,
       ROUND((m.customer_facing + COALESCE(m.unused_commitment, 0)) / o.orders * 1000, 2) AS with_unused_charged_back_per_1k
FROM monthly m JOIN monthly_orders o USING (month)
ORDER BY 1;
MonthUnused commitmentDirect / 1kWith unused charged back / 1k
2026-070.0016.3816.38
2026-081,439.9213.0113.93
2026-092,477.0810.8612.37

On August 15 the checkout fleet was cut, but its one-year Savings Plan was already paid for. FOCUS records the idle part as Usage rows with CommitmentDiscountStatus = 'Unused', here tagged to the platform team that owns the plan. Checkout’s unit cost drops to $10.86, but $1.51 of the real $12.37 per 1,000 orders just moved to another team’s line until the commitment is used or expires.

4. Pick the grain: divide sums, don’t average ratios

U3 · DuckDB
-- U3. Grain: daily ratios are noisy. Average the RATIO and you weight a quiet Sunday the same
--     as a peak day; divide the SUMS over a rolling window instead.
WITH daily AS (
  SELECT c.day,
         SUM(c.EffectiveCost) FILTER (WHERE c.cost_class = 'customer_facing' AND c.env = 'prod') AS cost,
         MAX(o.orders) AS orders
  FROM cost_classes c JOIN orders o USING (day)
  GROUP BY 1
),
windowed AS (
  SELECT day,
         cost / orders * 1000 AS daily_per_1k,
         AVG(cost / orders * 1000) OVER w AS avg_of_ratios_7d,
         SUM(cost) OVER w / SUM(orders) OVER w * 1000 AS ratio_of_sums_7d
  FROM daily
  WINDOW w AS (ORDER BY day ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
)
SELECT strftime(day, '%Y-%m-%d') AS day,
       ROUND(daily_per_1k, 2) AS daily_per_1k,
       ROUND(avg_of_ratios_7d, 2) AS avg_of_ratios_7d,
       ROUND(ratio_of_sums_7d, 2) AS ratio_of_sums_7d
FROM windowed
WHERE day IN (DATE '2026-07-07', DATE '2026-08-05', DATE '2026-09-02', DATE '2026-09-30')
ORDER BY 1;
DayDaily / 1k7-day avg of ratios7-day ratio of sums
2026-07-0717.6416.9116.78
2026-08-0516.2515.6515.53
2026-09-0212.0711.3511.26
2026-09-3011.3010.6610.57

Daily unit costs bounce with weekday volume. Over a window, divide total cost by total orders; averaging the daily ratios gives a quiet day the same weight as a peak day. The gap is small here and grows with how uneven your traffic is.

5. Check that cost actually moves with volume

U4 · DuckDB
-- U4. Is cost actually driven by orders? Index weekly orders and weekly customer-facing cost to
--     the first full week (= 100). If orders grow and cost does not, the falling cost per
--     order is a volume effect on mostly fixed capacity, not an efficiency gain, and it will
--     reverse if volume drops. (A cost-on-orders regression is tempting here, but both series
--     trend over time and the fleet changed size mid-quarter, so its slope is meaningless.)
WITH daily AS (
  SELECT c.day,
         SUM(c.EffectiveCost) FILTER (WHERE c.cost_class = 'customer_facing' AND c.env = 'prod') AS cost,
         MAX(o.orders) AS orders
  FROM cost_classes c JOIN orders o USING (day)
  GROUP BY 1
),
weekly AS (
  SELECT date_trunc('week', day) AS week, SUM(cost) AS cost, SUM(orders) AS orders, COUNT(*) AS days
  FROM daily GROUP BY 1
  HAVING COUNT(*) = 7
)
SELECT strftime(week, '%Y-%m-%d') AS week_starting,
       orders,
       ROUND(cost, 2) AS customer_facing_cost,
       ROUND(100.0 * orders / FIRST_VALUE(orders) OVER (ORDER BY week), 1) AS orders_index,
       ROUND(100.0 * cost / FIRST_VALUE(cost) OVER (ORDER BY week), 1)     AS cost_index,
       ROUND(cost / orders * 1000, 2) AS cost_per_1k
FROM weekly
ORDER BY week;
Week ofOrdersCostOrders indexCost indexCost / 1k
2026-07-06309,7455,143.33100.0100.016.61
2026-08-03340,7935,194.78110.0101.015.24
2026-08-17354,0594,093.09114.379.611.56
2026-09-21391,8224,156.81126.580.810.61

Orders grew 26.5% over the quarter while customer-facing cost barely moved, apart from one 20% step down at the downsizing. So most of the falling unit cost is a volume effect on capacity that is effectively fixed. It is good news while volume grows, and it reverses just as fast if volume falls. That is worth saying in the same sentence as the number. (We deliberately don’t fit a cost-on-orders regression here: both series trend over time and the fleet changed size mid-quarter, so its slope comes out negative and means nothing.)

6. Why EffectiveCost and not BilledCost

U5 · DuckDB
-- U5. Why not BilledCost? The same customer-facing numerator, billed instead of effective.
--     Covered usage bills at 0 because the Savings Plan was paid for upfront in July.
WITH monthly AS (
  SELECT date_trunc('month', c.day) AS month,
         SUM(c.EffectiveCost) FILTER (WHERE c.cost_class = 'customer_facing' AND c.env = 'prod') AS effective,
         SUM(c.BilledCost)    FILTER (WHERE c.cost_class = 'customer_facing' AND c.env = 'prod') AS billed
  FROM cost_classes c GROUP BY 1
),
monthly_orders AS (
  SELECT date_trunc('month', day) AS month, SUM(orders) AS orders FROM orders GROUP BY 1
)
SELECT strftime(m.month, '%Y-%m') AS month,
       ROUND(m.effective / o.orders * 1000, 2) AS effective_per_1k,
       ROUND(m.billed    / o.orders * 1000, 2) AS billed_per_1k
FROM monthly m JOIN monthly_orders o USING (month)
ORDER BY 1;
MonthEffectiveCost / 1kBilledCost / 1k
2026-0716.387.28
2026-0813.015.79
2026-0910.864.86

The checkout fleet runs mostly on a Savings Plan paid upfront in July, so its covered usage rows carry a BilledCost of 0. A BilledCost unit cost understates every month by more than half. Use EffectiveCost for unit economics; keep BilledCost for reconciling to invoices.

A short checklist before you publish a unit cost

  • Numerator written down: which teams, environments and charge categories, and why.
  • EffectiveCost, not BilledCost.
  • Shared platform cost allocated by a stated rule, not dropped.
  • Unused commitment charged to the workload it was bought for, or shown as its own line.
  • Ratios over windows computed as sum over sum.
  • A note on whether cost scales with the volume, so readers know if a falling number will hold.

Sources

Want guided practice on this?

FOCUS Billing Analysis with SQL is a 5-week, self-paced course built around the same kind of analysis: commitment reconciliation, anomaly detection and unit economics on a multi-cloud scenario. Week 1 is free. It is independent training and does not include the FinOps Foundation exam.