An identical Snowflake query reruns hourly yet never reuses the result cache — what would you check?
answer
- the text has to match, byte for byte
- some functions must be evaluated when the query runs
- a table that keeps loading keeps invalidating
- one session parameter turns reuse off entirely
- the executing role's grants are part of the match
basics
~20 sCheck for execution-time functions like CURRENT_TIMESTAMP, any DML or background rewrite on the referenced tables, query text that is not byte-identical because a tool injects comments or literals, USE_CACHED_RESULT set to FALSE, and a role lacking privileges on every referenced table.
solid answer
~50 sSnowflake reuses a stored result only when several conditions all hold, so diagnosis is a checklist. First, **the query text must match syntactically** — BI tools and orchestrators that inject a comment, a session id, or a rendered timestamp literal produce a different statement each run. Second, **no execution-time function**: `CURRENT_TIMESTAMP()` and similar non-deterministic functions, and non-deterministic UDFs or external functions, disqualify the result. Third, **the underlying data must be unchanged** — any DML on a referenced table invalidates the result, and so does background maintenance that rewrites micro-partitions, which is why a continuously loaded table almost never gets a cache hit. Fourth, **`USE_CACHED_RESULT`** may be `FALSE` in the session or the role's parameters. Fifth, **the executing role needs the required privileges on every table involved**. Finally, results expire 24 hours after last use, so a query run less often than that starts cold.
code
sql · 11 lines-- Never reusable: evaluated at execution time
SELECT country, SUM(amount)
FROM sales
WHERE order_ts >= DATEADD(hour, -24, CURRENT_TIMESTAMP())
GROUP BY country;
-- Reusable until the underlying data changes
SELECT country, SUM(amount)
FROM sales
WHERE order_ts >= DATEADD(day, -1, DATE_TRUNC('day', '2026-08-21'::date))
GROUP BY country;go deeper
Recall that a repeated query only comes back instantly when it is truly the same query on unchanged data — a filter containing the current time is a different query every run.
Be able to list the reuse conditions and explain why each exists: text match, no execution-time functions, unchanged data, the session parameter, and the role's privileges.
Demonstrate the diagnosis: pull both QUERY_TEXT values from QUERY_HISTORY, check bytes scanned, read Query Profile for a QUERY RESULT REUSE node, and separate a landing table from a stable serving object so results can survive.
Own the pattern-level fix — designing the serving layer so BI traffic is cacheable by construction, and deciding when a rolling window is worth its permanent compute cost instead.
## Why the checklist matters A result-cache hit is the cheapest outcome in Snowflake: no warehouse resumes, no warehouse credits. When a scheduled dashboard query misses every time, the account pays full compute for an answer it already has. The fix is almost always in the *query text or the loading pattern*, not in the warehouse. ## Condition 1 — syntactically identical text Snowflake matches the incoming statement against the stored one. A rendered date literal, an injected comment carrying a run id, a different alias, or a different amount of whitespace produces a different statement. This is the single most common cause in practice, because BI tools and schedulers love to template. ```sql -- Never reusable: a new literal every hour SELECT ... WHERE ts >= '2026-08-21 14:00:00'; -- Reusable across the whole day: a stable boundary SELECT ... WHERE ts >= DATE_TRUNC('day', '2026-08-21'::timestamp); ``` The practical remedy is to make the predicate stable at the granularity the business actually needs. An hourly dashboard that truncates to the day is reusable all day; one that pins to the current second never is. ## Condition 2 — no execution-time evaluation A result can only be reused if it would still be the same answer. Functions that must be evaluated when the query runs — `CURRENT_TIMESTAMP()` is the canonical example — disqualify it, as do non-deterministic user-defined functions and external functions. This is the second-most-common cause, and it hides inside otherwise innocent relative-time filters: ```sql -- Not reusable: evaluated at execution time WHERE event_ts >= DATEADD(hour, -24, CURRENT_TIMESTAMP()) ``` If the workload genuinely needs "last 24 hours", accept the miss or materialize a rolling aggregate the dashboard can read cheaply. ## Condition 3 — the data has not changed Any DML that changes a micro-partition of a referenced table invalidates stored results that depend on it, and so does background maintenance that rewrites micro-partitions. A table under continuous ingestion therefore invalidates results constantly. The architectural answer is to separate the *serving* object from the *landing* object: land into a raw table, refresh a stable aggregate on a schedule, and point the dashboard at the aggregate — which stays unchanged between refreshes and is therefore cacheable. ## Condition 4 — the session parameter `USE_CACHED_RESULT = FALSE` disables reuse. It is a legitimate benchmarking tool, and a classic accident: someone sets it in a session template, a role's parameters, or a connection's init statements while investigating performance and never puts it back. Check it explicitly with `SHOW PARAMETERS LIKE 'USE_CACHED_RESULT'`. ## Condition 5 — privileges of the executing role The cache is account-wide, but reuse requires the role running the query to hold the privileges needed on all tables the query references. A service role with narrower grants than the analyst who warmed the cache will not be served from it. Row access policies and other role-dependent security constructs likewise mean two roles are not asking the same question. ## Condition 6 — the retention window A result persists 24 hours from its last use, extended by each reuse up to 31 days from the original execution. A monthly report simply cannot hit the cache. A daily one is on the boundary; an hourly one is comfortably inside it — provided every other condition holds. ## How to confirm rather than guess Run the query twice by hand in one session and look at Query Profile: a hit renders as a single `QUERY RESULT REUSE` node. In `ACCOUNT_USAGE.QUERY_HISTORY`, a reused result shows essentially no bytes scanned and a millisecond-scale duration. If two supposedly identical runs both scan bytes, dump the two `QUERY_TEXT` values side by side — the difference is usually visible immediately, and usually a templated literal. ## What the fix is worth For a dashboard refreshed by many users against a table that changes a few times a day, converting a never-cacheable query shape into a cacheable one removes almost all of its compute cost, and it removes it without touching warehouse configuration at all. That is why "why isn't this cached?" is a better first question than "should we size up?".
- The dashboard genuinely needs a rolling 24-hour window. What do you do instead of chasing a cache hit?Accept that the predicate is not reusable and make the work small: maintain a pre-aggregated table or materialized view keyed by hour, so the dashboard scans a tiny rollup instead of raw events. Rounding the window boundary to the hour also lets one result serve every user within that hour.
- How do you prove a run was served from the result cache rather than just being fast?Query Profile shows a single QUERY RESULT REUSE node with no scan operators. In QUERY_HISTORY the run reports essentially zero bytes scanned with a millisecond duration, and no warehouse needed to be resumed. A merely fast run still shows TableScan operators and non-zero bytes scanned.
- Does cloning or renaming a table affect stored results for queries against it?Results are tied to the specific table data the query read. A clone is a separate object with its own identity, so queries against it do not inherit the source's cached results, and structural changes to the referenced object invalidate results that depended on it. Treat any DDL on a referenced table as invalidating.
saying these in an interview costs you the question
- Blames warehouse size for a repeated query that never caches
- Thinks whitespace or comment differences still count as identical
- Assumes CURRENT_TIMESTAMP filters are cacheable
- Forgets that any DML on a referenced table invalidates results
- Ignores that the executing role's privileges gate reuse