Frozen regions and backfill¶
Dynamic tables are defined by a query that Snowflake re-executes periodically to keep the table current. Each re-execution is called a refresh. A frozen region reduces refresh cost by telling Snowflake which rows to skip during refresh.
Note
Frozen regions were previously named immutability constraints, and the FROZEN WHERE clause previously used the syntax IMMUTABLE WHERE. The legacy IMMUTABLE WHERE syntax continues to be supported, and SHOW DYNAMIC TABLES still uses the immutable_where column.
| Clause | What it does | Acts on |
|---|---|---|
| FROZEN WHERE | Freezes dynamic table rows that match a predicate. Refresh skips those rows. | Output side |
The following example freezes output rows older than 30 days:
For the full dt_orders column list, see Create a dynamic table.
How frozen regions work¶
Rows that match the frozen region predicate are in the frozen region. Rows that don’t match are in the active region. During each refresh, Snowflake refreshes only the active region.
Key behaviors:
- Initial refresh: The predicate is ignored during initialization, and all rows are computed.
- Subsequent refreshes: Only the active region is refreshed, regardless of refresh mode.
- Reinitialization: Only the active region is refreshed during reinitialization.
- Storage lifecycle policies: If a dynamic table has both a storage lifecycle policy and a frozen region, the policy predicate acts as an additional frozen region. Rows that fall in both the frozen region and the expired region are still deleted when the policy runs. For more information, see Use storage lifecycle policies with dynamic tables.
Frozen region predicates can’t contain subqueries, nondeterministic functions (except timestamp functions), user-defined or external functions, or metadata columns. Columns in the predicate must be columns in the dynamic table, not columns from the base table. For the complete list of restrictions, see the Frozen region usage notes.
To check which rows are frozen, query the METADATA$IS_FROZEN metadata column:
Seed a dynamic table with BACKFILL FROM¶
BACKFILL FROM copies existing data into a new dynamic table without recomputing it. Use backfill to migrate existing pipelines, avoid expensive initialization when the table has years of historical data, or recover from data issues.
BACKFILL FROM is only available in CREATE DYNAMIC TABLE. You can’t add backfill to an existing dynamic table with ALTER.
The backfill source must contain matching columns with compatible data types in the same order as the dynamic table. You can also specify a point in time using the AT or BEFORE clause to copy data from a specific Time Travel snapshot.
When you combine BACKFILL FROM with a frozen region:
- The frozen region is cloned from the backfill source.
- The active region is computed from the definition.
The following limitations apply when you work with frozen regions and backfill:
- Currently, only regular and dynamic tables can be used for backfilling.
- You can’t specify policies or tags in the new dynamic table because they are copied from the backfill table.
- Clustering keys in the new dynamic table and backfill table must be the same.
You can also backfill from a specific Time Travel snapshot using the AT or BEFORE clause:
For the full dt_orders column list, see Create a dynamic table.
Add or remove a frozen region with ALTER¶
You can add, change, or remove a frozen region on an existing dynamic table. Adding a frozen region doesn’t trigger extra computation.
Change the frozen region predicate¶
To change the frozen region predicate, use ALTER DYNAMIC TABLE with the SET FROZEN WHERE clause:
Changing the predicate can trigger a reinitialization of the active region, depending on whether the change expands or shrinks the frozen region.
Changes that expand the frozen region (such as <= 2023 to <= 2024) don’t trigger
reinitialization. Changes that shrink or reshape the frozen region (such as < '2025-01-02'
to < '2025-01-01') do trigger reinitialization. Use the same ALTER DYNAMIC TABLE ... SET FROZEN WHERE syntax shown above with the new predicate.
Remove a frozen region¶
Caution
Removing a frozen region triggers a full reinitialization on the next refresh. This reprocesses all rows, including those that were previously in the frozen region.
To remove the frozen region, run ALTER DYNAMIC TABLE <name> UNSET FROZEN WHERE.
Verify a frozen region¶
To view the frozen region predicate on a dynamic table, run SHOW DYNAMIC TABLES and check
the immutable_where column. The column displays the predicate text, or NULL if no clause
is set:
To check individual row status, query METADATA$IS_FROZEN:
Interaction with RELY constraints¶
RELY constraints tell the optimizer to trust that a primary key or unique constraint holds, without enforcing it. When a dynamic table has both a frozen region and at least one RELY constraint, the columns in the predicate must appear in every RELY PRIMARY KEY and RELY UNIQUE constraint on the table. Put another way, predicate columns must be in the intersection of all RELY constraint column sets.
| Table constraints | Allowed in the frozen region predicate |
|---|---|
RELY primary key on (A, B), RELY unique on (B, C) | B only |
RELY primary key on (A), RELY unique on (A, B) | A only |
Snowflake validates this rule when you add or change either the predicate or a RELY constraint. If the resulting state violates the rule, the statement fails.
Note
RELY constraints can’t be declared in the CREATE DYNAMIC TABLE column list. To add a primary key or unique constraint to a dynamic table, use ALTER TABLE <name> ADD CONSTRAINT ... RELY after the table is created.
The following example succeeds because order_date is part of the RELY primary key:
The following example fails because order_status is not part of any RELY constraint:
What’s next¶
- For information about compute costs, see Understanding costs for dynamic tables.
- For query construct limitations that affect refresh mode, see Supported queries for dynamic tables.
- To monitor refresh operations, see Monitor dynamic tables.