Using Artie
Snowflake dynamic tables
Replicate high-throughput DynamoDB and Amazon Keyspaces tables into Snowflake by streaming every change into an append-only table and letting a Snowflake dynamic table keep the latest row per key.
Overview
By default, Artie keeps a Snowflake table up to date by merging each batch of changes into it. Each merge rewrites the affected micro-partitions, so very high change rates, common with DynamoDB and Amazon Keyspaces, can need a large warehouse to keep up.
With dynamic tables, Artie never merges. It streams every change into an append-only table with Snowpipe Streaming, and a Snowflake dynamic table keeps the latest row for each primary key. You keep querying the table by its usual name, which becomes a view.
Use this when you want to:
- Replicate a DynamoDB or Keyspaces table whose write volume is too high for merges to keep up with.
- Keep a full log of every change next to the current state of each row.
How it works
For a table named ORDERS, Artie creates three objects in the destination schema:
| Object | Type | What it holds |
|---|---|---|
ORDERS__ARTIE_CHANGES | Table | Every change Artie has read, appended in the order it arrives. Deletes are kept as rows with __ARTIE_DELETE = TRUE. |
ORDERS__ARTIE_LATEST | Dynamic table | The latest change for each primary key, built from ORDERS__ARTIE_CHANGES. |
ORDERS | View | The rows you query. It reads ORDERS__ARTIE_LATEST and leaves out deleted rows. |
Each change gets an __ARTIE_SEQ number that grows over time, and the dynamic table keeps the row with the highest __ARTIE_SEQ for each primary key:
CREATE DYNAMIC TABLE ANALYTICS.PUBLIC.ORDERS__ARTIE_LATEST
TARGET_LAG = '1 minute'
WAREHOUSE = DWH
REFRESH_MODE = INCREMENTAL
AS SELECT * FROM ANALYTICS.PUBLIC.ORDERS__ARTIE_CHANGES
QUALIFY ROW_NUMBER() OVER (PARTITION BY ORDER_ID ORDER BY __ARTIE_SEQ DESC NULLS LAST) = 1;The dynamic table uses the pipeline’s warehouse and refreshes incrementally, so each refresh only reads changes that arrived since the last one. The view hides __ARTIE_SEQ, and also __ARTIE_DELETE unless the pipeline has Soft-delete rows turned on (see Deletes).
Rows loaded by a backfill get __ARTIE_SEQ = 0, so any change streamed for the same key, before or after the backfill, wins over the backfilled row.
Before you start
-
Source: DynamoDB or Amazon Keyspaces.
-
Destination: Snowflake, with key-pair authentication. Dynamic tables are fed by Snowpipe Streaming, which needs a key pair.
-
Privileges: on top of the usual destination privileges, Artie’s role needs
CREATE DYNAMIC TABLE,CREATE VIEWandCREATE PIPE(for Snowpipe Streaming) on the destination schema, andUSAGEon the pipeline’s warehouse. Artie checks these when it validates the destination. These examples useARTIE_TRANSFER_ROLEandDWH, the defaults in the service account script, with theANALYTICS.PUBLICschema:SQLGRANT CREATE DYNAMIC TABLE ON SCHEMA ANALYTICS.PUBLIC TO ROLE ARTIE_TRANSFER_ROLE; GRANT CREATE VIEW ON SCHEMA ANALYTICS.PUBLIC TO ROLE ARTIE_TRANSFER_ROLE; GRANT CREATE PIPE ON SCHEMA ANALYTICS.PUBLIC TO ROLE ARTIE_TRANSFER_ROLE; GRANT USAGE ON WAREHOUSE DWH TO ROLE ARTIE_TRANSFER_ROLE; -
No existing table with the same name.
ORDERSbecomes a view, so it can’t already be a regular table. Enable dynamic tables on a table before it’s deployed. IfORDERSalready exists as a table, Artie stops before streaming any changes, with an error ending inis a regular table, so it can't become the dynamic table's view: drop or rename it, then re-backfill.
Steps
Grant the privileges
Run the grants in Before you start as a role that can grant them, such as
ACCOUNTADMIN.Turn on dynamic tables
Edit the pipeline, open the table’s advanced settings, and check Dynamic table. Set Target lag if you want something other than 1 minute. If you don’t see Dynamic table, ask the Artie team to turn dynamic tables on for your company.
Deploy the pipeline
Artie backfills the table into
ORDERS__ARTIE_CHANGES. The first time it streams a batch of changes for the table, it createsORDERS__ARTIE_LATESTand theORDERSview.Query the view
Query
ORDERSas you would any other table:SQLSELECT ORDER_ID, STATUS, UPDATED_AT FROM ANALYTICS.PUBLIC.ORDERS WHERE STATUS = 'shipped';Artie recreates the view with
COPY GRANTSwhenever the table gains columns, so grants onORDERSstay in place.
Target lag
The target lag is how far behind ORDERS__ARTIE_CHANGES the dynamic table is allowed to fall. It defaults to 1 minute.
To change it, edit the pipeline, open the table’s advanced settings, set Target lag, and deploy. After the deploy, Artie applies it to the dynamic table the next time it writes to the table.
- Format:
<number> <unit>, where the unit issecond,minute,hourorday, singular or plural. For example90 seconds,5 minutesor1 day. - Minimum: 1 minute. Snowflake doesn’t allow a lower target lag.
A longer target lag means fewer refreshes, so less warehouse time. Snowflake only resumes the warehouse for a refresh when the changes table has new rows. See Understanding costs for dynamic tables.
Deletes
A delete at the source is appended to ORDERS__ARTIE_CHANGES as a row with __ARTIE_DELETE = TRUE. It becomes the latest row for its key, so the dynamic table keeps it as a tombstone.
- Soft-delete rows off (default): the
ORDERSview leaves out deleted rows and doesn’t have an__ARTIE_DELETEcolumn. - Soft-delete rows on: the view keeps deleted rows and shows
__ARTIE_DELETE. A deleted row keeps its other column values only if the delete event carries them. For DynamoDB, that needs a stream view type ofNEW_AND_OLD_IMAGES.
Backfills
A re-backfill has to empty ORDERS__ARTIE_CHANGES first. Streamed rows always have a higher __ARTIE_SEQ than backfilled rows, so without emptying the table, a backfill couldn’t replace rows that are out of date.
In the backfill dialog, choose Empty tables first or Drop and recreate. For a dynamic table, Drop and recreate empties ORDERS__ARTIE_CHANGES instead of dropping it, since dropping it would break the dynamic table built on it. The dynamic table and view stay in place.
Keep existing rows and Rebuild and swap aren’t available for dynamic tables. Starting one returns table "public.orders" uses a dynamic table, so it can only be backfilled after truncating or dropping it.
Schema changes
When the source gains a column, Artie adds it to ORDERS__ARTIE_CHANGES and the dynamic table picks it up on its next refresh. Artie then recreates the ORDERS view so it includes the new column. If a refresh doesn’t add the column to the dynamic table, Artie recreates the dynamic table with CREATE OR REPLACE ... COPY GRANTS, which runs one full refresh.
Artie’s automatic schema changes skip tables that use dynamic tables, since Artie manages their columns itself.
Monitoring
Snowflake suspends a dynamic table after five refreshes in a row fail, and doesn’t resume it on its own. Artie checks the dynamic table’s state at most once a minute while it writes to the table. If Snowflake suspended it because of errors, Artie runs one manual refresh and, if that works, resumes it. A dynamic table that someone suspended by hand is left alone.
To check a dynamic table yourself:
SHOW DYNAMIC TABLES LIKE 'ORDERS__ARTIE_LATEST' IN SCHEMA ANALYTICS.PUBLIC;
SELECT name, state, refresh_action, refresh_start_time, refresh_end_time
FROM TABLE(ANALYTICS.INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(NAME => 'ANALYTICS.PUBLIC.ORDERS__ARTIE_LATEST'))
ORDER BY refresh_start_time DESC
LIMIT 20;Limitations
- DynamoDB and Amazon Keyspaces sources only. Other sources fail validation with
dynamic tables are only supported for DynamoDB and Amazon Keyspaces sources. - Snowflake destinations only.
- Can’t be switched on or off after the table is deployed.
ORDERSwould have to change between a table and a view. Remove the table from the pipeline and add it again instead. - Primary keys can’t change after the table is deployed. The dynamic table’s
PARTITION BYcan’t be altered. Remove the table and add it again instead. - Not combined with history mode, append-only mode, or soft partitioning.
- The changes table keeps every change. Artie doesn’t remove old rows from
ORDERS__ARTIE_CHANGES, so it grows with your change volume, and you pay Snowflake storage for it.
Frequently asked questions
Can I query the changes table directly?
Yes. ORDERS__ARTIE_CHANGES is a regular table with every change Artie has read, including __ARTIE_SEQ and __ARTIE_DELETE. Order by __ARTIE_SEQ to see a key’s changes in order. Don’t write to it, rename it, or drop it, since the dynamic table reads from it by name.
Why does a row show up in the changes table before the view?
The view reads the dynamic table, which Snowflake refreshes on its own schedule to stay within the target lag. A row is in ORDERS__ARTIE_CHANGES as soon as Artie streams it, and in ORDERS after the next refresh.
What happens if a batch is written twice?
If Artie retries a batch, its rows are streamed again with the same __ARTIE_SEQ values. The copies are identical, so the dynamic table still keeps the same row for each key.
Can I grant access to the view?
Yes. Grant SELECT on ORDERS as usual. Artie recreates the view and, when needed, the dynamic table with COPY GRANTS, so your grants are kept.