"Cached" means three different things
The word "cached" gets used loosely, but Snowflake actually maintains three independent caches with different scopes and different rules:
Result cache
The exact output of a previous query, held for 24 hours (reset up to 31 days on reuse). Requires a byte-for-byte identical statement. Doesn't need a running warehouse at all -- served entirely by the cloud services layer.
Warehouse (local disk) cache
Raw table data a running warehouse has already scanned, held on that warehouse's local SSD so a later query can skip re-reading it from remote storage. Dropped the moment the warehouse suspends.
Metadata cache
Per-micro-partition statistics -- min/max values, row counts -- always available regardless of warehouse state. Powers pruning, and can answer some trivial queries without a warehouse at all.
Which cache actually should have helped?
Answer three questions about the run
Walk through the same query's two runs and see which cache was actually eligible to help.
1. Was it the exact same SQL text re-run -- same case, same aliases, no CURRENT_TIMESTAMP()/RANDOM() -- by the same role, within the last 24 hours?
2. Has the underlying table been loaded, updated, deleted from, or automatically reclustered since the first run?
3. Did the query call a non-deterministic function (CURRENT_TIMESTAMP(), RANDOM(), UUID_STRING()) or an external function?
Why the result cache didn't apply
Full reuse requires every one of these at once: an exact syntax match (case, whitespace, and table aliases all count -- SELECT name FROM customers c and SELECT name FROM customers AS c are different statements as far as the cache is concerned), no non-reusable functions like UUID_STRING(), RANDOM(), or CURRENT_TIMESTAMP(), no external functions, unchanged source data, unchanged session parameters that affect the result, and a role with identical access to the one that ran it originally. Miss any single one of these and Snowflake reruns the whole query -- there's no partial credit.
Why the warehouse cache didn't apply
The warehouse cache lives on the compute nodes of one running warehouse and is dropped the moment that warehouse suspends -- including an automatic suspend after the configured idle timeout. If the "same" query ran an hour ago but the warehouse auto-suspended in between, the second run starts with a cold cache and re-reads from remote storage, regardless of how identical the query text is. The same gap can happen on a multi-cluster warehouse if a query lands on a different cluster than the one that scanned the data before -- each cluster's local disk cache is its own.
When it's not a caching bug at all
If the underlying table was loaded, updated, or automatically reclustered between the two runs, Snowflake correctly invalidates the cached result -- that's the cache doing its job, not failing at it. The same applies to the warehouse cache: if the table's micro-partitions changed, the cached blocks are stale and have to be refreshed. Re-running the full query in either case is the correct behavior, and "why didn't this stay cached" isn't the right question to be asking about it.
Key takeaways
- Result cache, warehouse cache, and metadata cache are three separate systems with three separate rules -- "it's cached" needs to specify which one.
- The result cache needs an exact syntax match, unchanged data, matching role, and no non-deterministic functions -- any single miss forces a full re-run.
- The warehouse cache is tied to that warehouse's lifecycle and is wiped on every suspend, including auto-suspend.
- A query hitting one cache layer says nothing about whether the other two also applied -- diagnose them independently.
Diagnostic checklist
Check PERCENTAGE_SCANNED_FROM_CACHE in QUERY_HISTORY to measure warehouse-cache benefit directly. For the result cache, there's no dedicated boolean column, but the signature is unmistakable: WAREHOUSE_SIZE IS NULL together with BYTES_SCANNED = 0 and a TOTAL_ELAPSED_TIME close to zero means the query never spun up a warehouse at all -- served entirely from the result cache or from metadata. The download below runs both checks.