A bigger warehouse breaks even at 3.6x, or at 2.1x if you change one default

  • Saurav Raj Joshi
  • 14 min read

360 model-runs at 30 seconds each is three hours of query time, 32.5 minutes of billed warehouse time and 65 credits a month, and the relation between those three is not what instinct suggests.

A Medium warehouse at 4 credits an hour bills 2.166667 credits for a nightly build of 360 model-runs: 1,350 seconds of wall-clock plus a 600-second auto-suspend tail. Over 30 nights that is 65 credits, $195 at list. A Large halves the wall-clock and bills 85 credits, $255 — 30.77% more for identical work.

Every figure below is quoted from a vendor document, or divided out in front of you.

How many Snowflake credits does a nightly batch need?

For the Kettlebridge build, 65 credits a month on a Medium warehouse, $195.00 at $3.00 a credit: Table 2(a), page 4 of Snowflake’s Service Consumption Table, On Demand, Enterprise, AWS US East (Northern Virginia), read 29 October 2026.

Kettlebridge is invented: a 31-person mooring and berth management software company, not a sector we work in. One build a night, one warehouse, one wake-up to pay for, every number picked rather than measured.

Four numbers run the calculation and you can state them all before buying anything: N, the query-runs in a batch; t, the mean execution seconds of one; c, how many run at once; S, the size. For Kettlebridge: 360, 30 seconds, 8 dbt threads, and the open question.

The fifth number is the one nobody touches, and it decides the answer. Snowflake’s CREATE WAREHOUSE reference gives the AUTO_SUSPEND default as 600, “the warehouse suspends automatically after 10 minutes of inactivity”, valid values “Any integer 0 or greater, or NULL”. Kettlebridge keeps it. That’s a choice, and section four prices it.

The same page hands you the quirk: the background process that suspends a warehouse “runs approximately every 30 seconds” and “isn’t intended for enabling precise control over warehouse suspension”, so the tail is 600 seconds plus up to 30 more — 0.033333 credits a night on a Medium. Small here. Not small later.

Pick the size last.

Credits per query-run: how to work out what one query costs

Credits per query-run, or CPQ, is the warehouse’s credits-per-hour divided by 3,600, times the query’s execution seconds, divided by the number of queries sharing the warehouse while it runs.

At Medium, 4 credits an hour, a 30-second model on 8 threads: (4 / 3600) x 30 / 8 = 0.00416667 credits. Fold the constants and CPQ is the hourly rate over 960, so every row below doubles the one above.

Credits an hour for standard and interactive warehouses, with CPQ derived from the standard column alone, for a 30-second query on 8 threads:

Size Gen1 standard credits/hour Interactive credits/hour CPQ (30 s, 8 threads)
X-Small 1 0.6 0.00104167
Small 2 1.2 0.00208333
Medium 4 2.4 0.00416667
Large 8 4.8 0.00833333

Standard rates are Snowflake’s overview of warehouses, interactive rates Table 1(d) on page 2 of the Service Consumption Table, and the ladder keeps doubling to 512 credits an hour at 6X-Large, where the same query costs 0.53333333. Price an interactive query off the CPQ column and you’re 40% out. Hold those rates; section seven comes back for them.

CPQ covers warehouse compute and nothing else. Serverless features bill off Table 5, pages 16 and 17 of 25, which multiplies page 1’s “one Platform Credit per Compute-Hour” by 2 for materialised view maintenance, 0.9 for serverless tasks.

Convert query seconds into warehouse hours before you pick a size

Query seconds over concurrency gives wall-clock seconds, and wall-clock plus the auto-suspend tail is what the meter bills.

Take it a rung at a time. 360 model-runs times 30 seconds is 10,800 query-seconds, 180 minutes, 3.0000 hours, and over 8 threads that is 1,350 seconds of wall-clock, 22.5 minutes. Add the 600-second tail. The warehouse is awake 1,950 seconds, 0.541667 hours, which at 4 credits an hour is 2.166667 credits a night, 65.0000 over 30 nights.

Now the same number from the other end, borrowing none of those minutes. CPQ at Medium is 0.00416667, so 360 of them is 1.500000 credits of work a night. The idle tail is its own term, charged once per wake-up: 600 / 3600 x 4 = 0.666667. And 1.500000 + 0.666667 = 2.166667, the top-down figure to six places.

Sum-of-CPQ alone gives 45.0 credits a month, wrong by $60.00. The correction isn’t new — select.dev’s cost-per-query post made it in April 2024: Snowflake “does not charge per second a query ran. They charge per second the warehouse is up.” That post attributes spend after the fact, this one predicts it beforehand, so here the tail keeps a term of its own. Page 1 of the Service Consumption Table puts the rate on the warehouse “while the applicable Virtual Warehouse or Compute Node is in operation”. In operation, not in query. Work over billed is 1.500000 / 2.166667, a little under 70%.

python

# Warehouse credit calculator. Substitute your own numbers and re-run.
CREDITS_PER_HOUR = 4      # Medium, Gen1 standard
AUTO_SUSPEND     = 600    # seconds; Snowflake's documented default
QUERY_SECONDS    = 30     # t, mean execution time of one query-run
QUERIES          = 360    # N, query-runs in the batch
CONCURRENCY      = 8      # c, e.g. dbt threads
WAKES_PER_DAY    = 1
DAYS             = 30
PRICE_PER_CREDIT = 3.00   # On Demand list, Enterprise, AWS US East (N. Virginia)

cps   = CREDITS_PER_HOUR / 3600                 # 0.00111111
cpq   = cps * QUERY_SECONDS / CONCURRENCY       # 0.00416667
work  = QUERIES * QUERY_SECONDS / CONCURRENCY   # 1350.0 s of wall-clock
idle  = WAKES_PER_DAY * AUTO_SUSPEND            # 600 s
awake = work + idle                             # 1950.0 s
day   = awake * cps                             # 2.166667 credits
print(round(cpq, 8), awake / 60, round(day, 6),
      round(day * DAYS, 4), round(day * DAYS * PRICE_PER_CREDIT, 2))
# 0.00416667 32.5 2.166667 65.0 195.0

No public credit calculator I’ve opened takes auto-suspend, concurrency or a query count.

A Large warehouse costs 31% more than a Medium even when it is twice as fast

A Large warehouse bills 85 credits a month against a Medium’s 65 for the same nightly build, 30.77% more, and the extra buys 11.25 minutes off a 22.5-minute window.

Large is 8 credits an hour. Assume it scales perfectly, the generous case. Wall-clock halves to 675 seconds, the warehouse is awake 1,275 seconds, 0.354167 hours, 2.833333 credits a night, 85.0 a month. And 2.833333 / 2.166667 = 1.30769.

The step bought wall-clock and sold you a doubled idle tail.

Work the units and the reason stops being surprising. The work portion of the bill is wall-clock seconds times credits per hour, and a size step halves the first while doubling the second. At Medium that product is 1,350 x 4 = 5,400. At Large, 675 x 8 = 5,400, and either over 3,600 is the 1.5 credits of work the CPQ route produced. So the work term is invariant and only the idle term moves, which is the arithmetic under our size-up test. Idle at Medium is 600 x 4 / 3600 = 0.666667 credits and at Large 1.333333, and that difference of 0.666667 a wake-up is the whole gap between the bills.

In general form, with perfect scaling: a size step changes the work portion by nothing and adds exactly (auto_suspend_seconds x credits_per_hour / 3600) credits per wake-up.

So when does Large actually pay? Set the bills equal and solve for the speed-up k: (1350/k + 600) x 8 = 7,800 gives 1350/k = 375 and k = 3.6, so the batch has to run 3.6 times faster, not twice. And 2x isn’t a straw man — espresso.ai’s warehouse sizing guide gets “break-even occurs at exactly 60 seconds” on a Large against 120 on a Medium. No idle term in it.

Read that backwards and the 31% stops being a fact about warehouse sizes. It is a fact about 600. Set AUTO_SUSPEND to 60 and the Medium is awake 1,410 seconds, 1.566667 credits a night; the Large 735 seconds, 1.633333. The premium drops to 4.26%, and (1350/k + 60) x 8 = 5,640 gives k = 2.093, so 2x very nearly is enough and the decision flips. The sweeper bites here too: a tail landing at 90 seconds moves break-even to 2.14, so 2.09 to 2.14 is the honest width and I wouldn’t quote it tighter.

What Snowflake’s credits-per-second column gets wrong

0.0003 x 3600 is 1.08, not 1.

Snowflake’s overview of warehouses prints credits per hour and credits per second side by side, and the second doesn’t multiply back into the first. X-Small reads 1 and 0.0003; Small reads 2 and 0.0006. Both are rounded to four places and both come back 8.0% high. Medium reads 0.0011 against a stated 4, which multiplies out to 3.96, a 1.0% shortfall that repeats down the middle of the ladder. Take a calculator to any row.

Price Kettlebridge’s 1,950 awake seconds off the printed Medium figure and the night comes out at 2.145 credits against a true 2.166667 — 0.65 credits a month, $1.95 at list. Nobody is going to miss two dollars. But the error at the bottom of the ladder runs eight times larger and in the opposite direction, so derive credits per second as credits per hour over 3,600 and never read the printed column.

Databricks DBU pricing and the 45-minute Auto Stop default

A DBU costs $0.70 on Premium Serverless SQL, $0.55 on Premium SQL Compute Pro and $0.22 on Premium SQL Analytics, read from Microsoft’s Azure Retail Prices API for East US on 29 October 2026, each per DBU-hour.

Each prices one DBU, not one hour of warehouse, and the missing rung is how many DBUs an hour a size burns. I could not close it, and I’d rather name the gap: the Databricks pricing page for SQL renders its table in JavaScript and returns the literal string “Loading…” to a fetch, and the sizing documentation never mentions DBUs. Pull your own rate from usage_quantity in system.billing.usage. Nor will I pretend $3.00 a credit is what a buyer pays. It’s list, and nobody on a capacity contract really pays list.

What carries across is the shape of the idle term. The page on creating a SQL warehouse gives the serverless Auto Stop default as “10 minutes”, Snowflake’s 600 seconds exactly, so on serverless the two are a draw and I won’t claim otherwise. On pro and classic it is “45 minutes, which is recommended for typical use”. Run Kettlebridge’s 1,350 seconds behind that and the warehouse is awake 4,050 seconds, 67.50 minutes against 32.50, so idle is 66.7% of the bill rather than 30.8%.

The interactive warehouse is 40% cheaper an hour and cannot suspend for 24 hours

An interactive Medium warehouse bills 2.4 credits an hour against a standard Medium’s 4, 40% less, and it would cost Kettlebridge more.

The honest case is the rate card: Table 1(d), page 2 of the Service Consumption Table, effective 15 October 2026, prints interactive rates from 0.6 to 76.8 an hour, every rung 60% of the standard. Two floors undo it, on page 1:

when an Interactive Warehouse (a type of Virtual Warehouse) is started or resumed, a minimum of sixty (60) minutes’ worth of Platform Credits will be consumed … Thereafter, Virtual Warehouses and Compute Nodes will be charged on a per second basis, rounded up to the nearest whole second.

So a 22.5-minute batch bills a full hour: 2.4 credits against a standard Medium’s 2.166667, 10.77% dearer. And that’s the good case, because it assumes somebody suspends the thing by hand. Snowflake’s page on interactive analytics says “The minimum AUTO_SUSPEND value for an interactive warehouse is 86400 seconds (24 hours)”, so nothing times out after the batch and left alone it bills 24 x 2.4 = 57.6 credits a day, 26.58 times the standard warehouse’s night.

There is a regime where it wins outright, and this isn’t it: a dashboard warehouse awake through a 10-hour day, suspended on a schedule, bills 10 x 2.4 = 24 credits against 10 x 4 = 40.

I wouldn’t put Kettlebridge’s nightly build on an interactive warehouse, and I wouldn’t move it to Gen2 on the 35% premium alone.

Run the estimate again with the runtime four times longer

Derate t from 30 seconds to 120 and the monthly bill triples. The Medium-against-Large answer doesn’t move by a single credit.

At t = 120, 360 x 120 = 43,200 query-seconds is 12.00 hours, and over 8 threads 5,400 seconds of wall-clock. Medium is then awake 6,000 seconds, Large 3,300: 6.666667 credits a night against 7.333333, 200.0 a month against 220.0. And 6.666667 / 2.166667 = 3.077, with the nightly gap of 0.666667 exactly where it was. It never was a function of the workload.

Double the volume and the same thing happens: N = 720 gives 2,700 seconds of wall-clock, and the gap is again 0.666667.

Credits a month and dollars at $3.00 list, across the three cases:

Case Medium Large Gap
Base: t = 30 s, N = 360 65.0 cr, $195.00 85.0 cr, $255.00 20.0 cr, $60.00
Runtime 4x: t = 120 s 200.0 cr, $600.00 220.0 cr, $660.00 20.0 cr, $60.00
Volume 2x: N = 720 110.0 cr, $330.00 130.0 cr, $390.00 20.0 cr, $60.00

The size decision doesn’t flip. The window decision does: 22.5 minutes becomes 1.5 hours, which is a different argument about when the build starts.

When does a bigger warehouse size pay for itself?

At 3.6x on Snowflake’s Gen1 ladder, and roughly 1.6x for a Gen2 step on AWS. Table 1(b), page 2 of the Service Consumption Table, prices a Gen2 Medium on AWS at 5.4 Platform Credits an hour against Gen1’s 4, so (1350/k + 600) x 5.4 = 7,800 gives k = 1.5987, and the Azure rate of 5.0 gives 1.4063 — both well past the 1.35x premium the rate card invites you to read as the hurdle. The tail doesn’t scale.

One more threshold, and it decides schedules rather than sizes. We don’t sign off a schedule where the idle tail is more than half the bill. Kettlebridge’s build holds the warehouse 1,350 seconds, so idle equals work at wake-ups x 600 = 1,350, or about 2.25 a night. Below that, leave the tail out of a rough estimate. Split the build into three waves and idle beats the work, and we wouldn’t sign it off.

Predict first, then read the meter a week later.

sql

SELECT DATE_TRUNC('day', start_time)               AS day,
       warehouse_name,
       SUM(credits_used_compute)                   AS compute,
       SUM(credits_attributed_compute_queries)     AS attributed,
       SUM(credits_used_compute)
         - SUM(credits_attributed_compute_queries) AS idle_and_unattributed
FROM   SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
WHERE  start_time >= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND  warehouse_name = 'KETTLEBRIDGE_BUILD'
GROUP  BY 1, 2
ORDER  BY 1;

The metering view’s documentation puts latency at “up to 180 minutes (3 hours)”, so don’t read last night’s run at breakfast, and the attributed column “doesn’t include warehouse idle time usage”, which is the one quantity this whole argument turns on. Predicted 2.166667 a night against a metered 2.17 is a model that works. A metered 5 means something wakes that warehouse that isn’t in your four inputs, and finding it is an afternoon of data engineering work.

Tell us what’s broken.

Twenty minutes, no deck. We’ll tell you straight whether this is work we should be doing, and if it isn’t, we usually know who should.

We come back within one business day.