A practitioner's reference covering all 11 Snowflake cost domains, 93 actionable optimizations, and how to build automated governance that actually sticks.
Every dollar spent in Snowflake falls into one of these 11 domains. Understanding each domain's billing mechanics is the prerequisite for any cost optimization effort.
AI_CLASSIFY charges labels × rows in tokens. Expensive models for simple tasks cost 10–50× more.dbt and BI tools span multiple domains simultaneously — they drive warehouse compute, cloud services overhead, and storage accumulation. They deserve dedicated optimization passes separate from your warehouse tuning.
See Pages 6–7 for domain-specific recommendations for dbt models, DAG efficiency, BI refresh patterns, and metadata polling reduction.
Per-second billing with 60-second minimum per resume. Warehouse size doubles credit consumption at every tier. Credits burn while the warehouse is RUNNING, even with zero active queries.
| Problem | Recommendation | Impact |
|---|---|---|
| Idle warehouses running | Set AUTO_SUSPEND=60s (ETL), 300s (interactive) | 15–40% savings |
| Oversized warehouses | Downsize if avg execution <10s or low scan percentage | 50% per tier |
| Underused warehouses (<5% util) | Consolidate compatible workloads onto fewer warehouses | 30–60% fewer idles |
| Wrong scaling policy | Economy policy for batch; Standard for interactive concurrency | Avoids over-scale |
| Queries spilling to disk/remote | Upsize warehouse OR optimize query first | 2–10× speed |
| Full table scans (no pruning) | Add clustering keys on filter columns | 80–95% fewer partitions |
| No result cache utilization | Enable USE_CACHED_RESULT; fix non-deterministic functions | Zero credits |
| 24/7 WH for 8-hour workloads | Schedule suspend/resume with resource monitor or task | 65% savings |
| Runaway queries (no timeout) | Set STATEMENT_TIMEOUT_IN_SECONDS=3600 per warehouse | Prevent runaway |
| Resume/suspend thrashing | Increase auto-suspend; batch tiny jobs together | No 60s penalty |
| No query-to-warehouse routing | Route complex queries to large WH, simple to small WH | Cost aligned |
| No attribution / query tagging | Implement QUERY_TAG standard for all pipelines | Chargeback↑ |
| BI dashboard refresh storms | Stagger refresh schedules; dedicate a BI-specific warehouse | Peak -40–60% |
| Problem | Fix | Impact |
|---|---|---|
| Tiny Snowpipe files (<100MB) | Batch to 100–250MB before load | 30–50%↓ |
| Over-clustering (wrong columns) | Use low-cardinality filter columns only | 50–80%↓ |
| MVs refreshing but unqueried | Drop where refresh cost > query savings | Eliminate waste |
| Dynamic Table TARGET_LAG too short | Set maximum acceptable staleness | 10–15×↓ |
| DT using FULL refresh mode | Set REFRESH_MODE=INCREMENTAL | 10–100×↓ |
| Many small serverless tasks | Consolidate with longer intervals | Less overhead |
| SOS on tables without lookups | Remove Search Optimization from unused tables | Eliminate waste |
| DTs not using DOWNSTREAM | Set intermediate DTs to DOWNSTREAM dependency | Fewer refreshes |
| Problem | Fix | Impact |
|---|---|---|
| CS exceeding 10% threshold daily | Reduce metadata-heavy operations, batch SHOW calls | No billed CS |
| BI tools polling every 30s | Client-side caching; reduce refresh intervals | Less SHOW ops |
| File listing overhead (large stages) | Use directory tables, partitioned external stages | Big savings |
| Many short-lag Dynamic Tables | Increase TARGET_LAG; use DOWNSTREAM chaining | Less scheduling |
DATA_RETENTION_TIME_IN_DAYS=1 on staging tables immediately.| Problem | Fix | Impact |
|---|---|---|
| High TT on staging tables | DATA_RETENTION_TIME_IN_DAYS=1 | Up to 90×↓ |
| Permanent tables for temp data | Use TRANSIENT for staging / work tables | No failsafe |
| Uncleared internal stages | Set PURGE=TRUE or run REMOVE after load | 100% recovery |
| Abandoned tables (>90d no access) | Audit ACCESS_HISTORY and drop unused tables | Immediate |
| High-churn tables with failsafe | Convert to TRANSIENT + periodic backup strategy | 10–16×↓ |
| Poor clustering depth (>4) | Recluster where SYSTEM$CLUSTERING_DEPTH > 4 | Less overlap |
| Unused MV storage (0 queries 30d) | Drop materialized views with no recent access | Reclaim storage |
| Problem | Fix | Impact |
|---|---|---|
| Expensive models for simple tasks | Use smaller models (mistral-7b, llama3-8b) | 10–50×↓ |
| Verbose system prompts | Minimize prompt length; efficient instructions | 30–60% token cut |
| Large WH for AI functions | Use MEDIUM or smaller; AI is not WH-bound | 4–8× WH savings |
| No per-user AI credit budget | Set monthly credit limits per role/user | Prevent blowouts |
| Row-by-row AI processing | Batch calls; process in bulk during off-peak | Throughput↑ |
| Duplicate AI processing (same input) | Cache results for repeated identical inputs | No re-work |
| Over-provisioned Cortex Search | Suspend inactive search services immediately | Eliminate idle |
| RAG over-fetching context | Reduce retrieval K; filter relevance threshold | 30–50% gen cut |
| Problem | Fix | Impact |
|---|---|---|
| Cross-region COPY INTO | Use same-region staging buckets | Eliminate egress |
| Over-frequent cross-region replication | Reduce schedule for stable databases | Less transfer |
| No ECO for multi-region listings | Enable Egress Cost Optimizer — pay once | Large savings |
| Large result sets to client | Filter/aggregate before returning; use stages | Egress↓ |
| Problem | Fix | Impact |
|---|---|---|
| Pools running 24/7 | Set AUTO_SUSPEND_SECS, MIN_NODES=0 | Active billing |
| GPU for non-GPU workloads | Use CPU instance families instead | 5–10× savings |
| Notebooks left running idle | Idle timeout policy + user education | Kill idle cost |
| System CPU pool 3-day suspend | Reduce to AUTO_SUSPEND_SECS=600 | No 3-day idle bill |
| Persistent services vs. jobs | Convert long-running services to jobs | Per execution |
| Over-provisioned MAX_NODES | Set based on actual observed peak concurrency | Prevent blowout |
| Problem Pattern | Recommended Fix | Impact |
|---|---|---|
| Full refresh on large models every run | Convert to config(materialized='incremental') | 80–95% less compute |
| DAG over-materialization | Use ephemeral models; reduce intermediate tables | Storage+compute↓ |
| Duplicate transformations across models | Consolidate shared logic into a single base model | Less redundancy |
| Cascade rebuild on parent model change | Use incremental + is_incremental() guard | No cascade |
| dbt tests running on prod warehouse | Route test targets to smaller dedicated WH | 50%+ WH savings |
| SCD2 snapshots running too frequently | Reduce frequency/scope to necessary tables only | Less compute |
| dbt jobs conflicting with BI refresh peak | Offset dbt schedule from BI refresh windows | Less contention |
| Problem Pattern | Recommended Fix | Impact |
|---|---|---|
| Dashboard refresh storms at top of hour | Stagger refresh schedules across time slots | Reduce peak 40–60% |
| Tableau / Power BI extract refreshes repeating | Switch to live connection where data freshness allows | Data pulled↓ |
| BI tool metadata polling every 30s | Connection pooling; increase poll intervals | Less Cloud Svc |
| Low cache hit rate on dashboards | Fix dynamic NOW()/CURRENT_TIMESTAMP in filters | Cache hits↑ |
| Oversized dedicated BI warehouse | Right-size WH; monitor utilization% per dashboard | Right-sized |
| No BI query tagging or attribution | Tag BI queries via QUERY_TAG per dashboard/team | Chargeback↑ |
| Anti-Pattern | Root Fix | Impact |
|---|---|---|
SELECT * on wide tables with 100+ columns | Select only required columns explicitly in every query | 30–80% scan↓ |
| VARIANT / OBJECT parsed at query time | Flatten JSON at ingest; persist as typed columns | 2–5× faster |
| Window functions over very large partitions | Tighten PARTITION BY scope; pre-filter where possible | Proportional↓ |
| Micro-partition skew on large fact tables | Rebuild table with even distribution key | Better pruning |
| Mixed ETL / BI / ad-hoc on one warehouse | Isolate by workload class into dedicated warehouses | No contention |
| Identical queries missing result cache | Standardize patterns; remove dynamic timestamps | Zero credits |
| Shadow IT / unowned pipeline resources | Audit via QUERY_HISTORY; assign ownership tags | Governance↑ |
| Unintended Cartesian product / cross join | Add explicit JOIN conditions; validate with EXPLAIN | Can 10–100× compute |
| Correlated subquery executing per row | Rewrite as explicit JOIN or CTE with single pass | 2–10× faster |
| Warm credits >20% of total consumption | Right-size AUTO_SUSPEND per arrival pattern | 15–20% savings |
QUERY_TAG to enable team-level chargebackACCOUNT_USAGE.ACCESS_HISTORY to detect orphaned resourcesWAREHOUSE_METERING_HISTORY for warehouses with zero queries but non-zero creditsAUTO_SUSPEND=60s for batch WHDATA_RETENTION_TIME_IN_DAYS=1PURGE=TRUE on COPY INTOmaterialized='incremental'REFRESH_MODE=INCREMENTALAUTO_SUSPEND_SECS=600| Anti-Pattern | Root Fix | Impact |
|---|---|---|
| Redundant computation across 3+ models | Single intermediate materialization | No dup credits |
| Query perf regression over time | Decompose: growth vs. decay vs. contention | Stops drift |
| Functionally identical queries (cache miss) | Standardize patterns for cache hits | Zero credits |
| VARIANT/OBJECT parsed at runtime | Flatten at ingest time into typed columns | 2–5× faster execution |
| Window functions on huge partitions | Tighten PARTITION BY clause | Proportional↓ |
| Micro-partition skew on large tables | Rebuild table with even distribution | Better pruning |
| Warm credits >20% of total | Right-size auto-suspend per arrival pattern | 15–20% savings |
| Problem | Fix | Impact |
|---|---|---|
| RAG over-fetching context | Reduce retrieval K; filter relevance threshold | 30–50% tokens↓ |
| Embeddings regenerated for unchanged data | Cache embeddings; regenerate only on change | No reprocessing |
| Cortex Analyst model too broad | Scope to relevant tables/columns per question type | 40–60% tokens↓ |
| AI agents firing on noise | Add outcome validation; reduce trigger frequency | No wasted runs |
| Fine-tuning when few-shot works | Try prompting/few-shot first before fine-tuning | No training cost |
| Cortex Search over-rebuilding | Match refresh cadence to actual data churn rate | 50–80% rebuild↓ |
| Document AI reprocessing unchanged docs | Track doc hashes; skip on no change | Eliminate waste |
| No per-tenant AI attribution (ISV) | Implement tenant-level token tracking | Margin analysis |
QUERY_TAG to enable team-level chargebackACCOUNT_USAGE.ACCESS_HISTORY to detect shadow IT and orphaned resources| Problem Pattern | Recommended Fix | Impact |
|---|---|---|
| Marketplace app running 24/7 warehouse | Check app WH config; set auto-suspend to 60s | Large savings |
| Cross-region marketplace delivery | Use same-region provider account; enable ECO | Eliminates egress |
| Listing with AUTO_FULFILLMENT enabled | Disable auto-fulfillment on low-demand listings | No idle compute |
| Provider replicating to all regions | Limit replication to regions with active consumers | Egress cost down |
| Shared DB queried without local cache | Materialize frequently-joined shared data locally | No remote scan |
| Unused marketplace trials still active | Audit and terminate inactive app trials monthly | Remove idle cost |
DATA_SHARING_USAGE.LISTING_CONSUMPTION_DAILY to see which consumers drive your provider costs.| Monitor Type | Configuration | Benefit |
|---|---|---|
| Account-level monitor | Monthly credit quota; alerts at 75/90/100% | Global safety net |
| Per-warehouse monitor | Individual quota per WH aligned to workload | Team-level control |
| Dev / sandbox warehouses | Weekly reset + suspend-at-100% to hard-cap | No runaway dev |
| Cortex AI heavy roles | Role-level monitor on AI-heavy roles monthly | AI budget control |
| Alert routing | Route alerts to Slack or email via Tasks | Fast response |
APEX monitors all 11 Snowflake cost domains in real time, automatically routes anomalies to the right owner, and generates verified savings reports — without adding headcount or engineering toil.