Hook
Your Snowflake warehouses bill for ten idle minutes after every job that runs on them. That is the AUTO_SUSPEND default, 600 seconds, and it fits an analyst better than it fits your jobs.
Nobody chose that number. It shipped as the default, and it survives because idle time on a running warehouse looks like nothing at all.
The finding
A Medium warehouse running twelve scheduled jobs a day burns 176 idle credits a month, the credits the meter runs up with nothing running on it. Modeled: 4 credits/hour on a Gen1 Medium × (10 ÷ 60) hours × 12 jobs × 22 working days = 176 credits a month, at the 600-second default. Substitute your own size and cadence.
Twelve hourly jobs across a twelve-hour day is the assumed cadence, and 22 working days is the assumed month. Put your own working days in place of the 22. This does not apply to a warehouse whose queries arrive closer together than ten minutes, because it never suspends and never goes idle.
It does not apply to an Adaptive Warehouse, which is Snowflake's managed compute service, because there you no longer set suspend and resume policies at all.
The mechanism
AUTO_SUSPEND defaults to 600 seconds on a standard warehouse, and for an analyst typing queries that is the right number. Their next query could land at any moment, and paying for the wait beats paying the resume delay every time. Snowflake bills warehouse compute per second, with a 60-second minimum every time the warehouse starts.
Scheduled jobs are the opposite of an analyst. A job that finishes and does not run again for an hour leaves ten billed idle minutes behind it.
Size is what turns this from a rounding error into a line on the invoice. Credits double with every size step, so those twelve jobs on a Gen1 2X-Large at 32 credits/hour cost 32 × (10 ÷ 60) × 12 × 22 = 1,408 credits a month. Your own warehouse size and job count go in place of the 2X-Large and the twelve.
The obvious fix is to set AUTO_SUSPEND to something under a minute, and it backfires in two ways. Snowflake's own guidance says there is no benefit to stopping a warehouse inside that first 60 seconds, because the credits are already billed.
A warehouse resumed every couple of minutes buys that minute again and again. Suspending also drops the warehouse cache, which slows the first queries after a resume. Snowflake recommends matching the setting to the gaps between your queries, the dark time from one query ending to the next arriving, rather than a universal value.
What to do about it
- Read the auto-suspend seconds on every warehouse your role can see.
SHOW WAREHOUSESlists the warehouses you have privileges on, and any warehouse that comes back at 600 is running the default. That is ten idle minutes after each job, and it takes a minute to check. - Start with the biggest warehouse on that list. An idle X-Small is a rounding error and an idle 2X-Large is the invoice. Fix the top row before you touch anything else.
- Set
AUTO_SUSPENDon that one warehouse to cover the quiet stretches inside a job, and never below 60 seconds. Below the minimum charge there is nothing left to save. Your scheduler already holds the job times, so this needs no query history and no second grant. - Do nothing on a warehouse whose queries arrive closer together than its auto-suspend. A warehouse under constant query traffic never suspends and never goes idle, so
AUTO_SUSPENDis not costing you anything there. Go look at storage or at a single expensive model instead. - Check
MIN_CLUSTER_COUNTtoo, on Enterprise or higher. It defaults to 1, and anything above that floor pays for extra clusters whenever it runs. Set it back to 1 unless a named service needs it. Standard accounts can skip this one, because multi-cluster warehouses need Enterprise Edition.
Audit Tip of the Week
How many of your warehouses are still sitting at the 600-second auto-suspend default?
Run this (Snowflake): No ACCOUNT_USAGE grant, and it lists only the warehouses your own role can see. The SHOW needs no running warehouse.
-- Warehouses your role can see that are still on the 600-second auto-suspend default.
-- Read-only. Metadata only: SHOW WAREHOUSES, post-processed with RESULT_SCAN.
-- No ACCOUNT_USAGE grant, and no user data.
show warehouses;
select count(*) over () as warehouses_at_600,
"name" as warehouse,
"size" as warehouse_size,
"auto_suspend" as auto_suspend_seconds
from table(result_scan(last_query_id()))
where "auto_suspend" = 600
order by "name";
What you're looking for. Every row the query returns is a warehouse still on Snowflake's documented default, and the count is your number. (Databricks: same question, for auto-stop on a SQL warehouse.) A count of zero is a clean result.
What it means. Each of those warehouses bills ten idle minutes after every job that runs on it. On a Gen1 Medium running twelve jobs a day that is the 176 idle credits a month this issue models, and it scales with size. Set AUTO_SUSPEND on your largest one to cover the quiet stretches inside a job.
Reply with your number. I aggregate every reply and publish the distribution, never attributed. Forward this to whoever owns the bill: Query Debt.
Sign-off
Hit reply with how many of your warehouses came back at 600. I read them all.