Snowflake Dynamic Tables vs Views: Wat is het Verschil?

Gepubliceerd: 1 augustus 2026
Leestijd: 14 minuten
Dataplatformen · Snowflake

Een view, een materialized view of een Dynamic Table — Snowflake geeft je drie manieren om een transformatie te definiëren, elk met een ander antwoord op de vraag "hoe vers moet deze data zijn, en wat mag dat kosten?" In deze gids leggen we het verschil uit, met SQL-voorbeelden, een vergelijkingstabel en een beslisboom voor je volgende pipeline.

Het Verschil in Één Alinea

Een view in Snowflake slaat geen data op — het is een opgeslagen query die bij elke SELECT opnieuw wordt uitgevoerd tegen de onderliggende tabellen. Een Dynamic Table slaat het resultaat van een query wél fysiek op en houdt dat automatisch en incrementeel actueel, volgens een door jou ingesteld verversingsdoel: de TARGET_LAG.

Het is in de kern dezelfde afweging als bij incremental load vs full load: bereken je opnieuw bij elke aanvraag, of houd je een vooraf berekend resultaat actueel? Alleen speelt die afweging hier binnen Snowflake zelf, op het niveau van transformatielagen.

In één zin

Views zijn goedkoop in rust, duur bij veel queries op grote datasets. Dynamic Tables zijn duur in rust (ze verversen ook als niemand kijkt), maar goedkoop en snel bij veel queries — met een expliciete knop om latency tegen kosten af te wegen.

Wat is een View in Snowflake?

Een standaard VIEW is niets meer dan een naam voor een query. Er wordt geen data opgeslagen — Snowflake voert de onderliggende SELECT uit op het moment dat iemand de view bevraagt.

-- Standaard view: geen opslag, altijd realtime, altijd herberekend
CREATE OR REPLACE VIEW analytics.v_omzet_per_klant AS
SELECT
    k.klant_id,
    k.naam,
    SUM(o.bedrag) AS totale_omzet,
    COUNT(o.order_id) AS aantal_orders
FROM raw.klanten k
JOIN raw.orders o ON o.klant_id = k.klant_id
GROUP BY k.klant_id, k.naam;

Voordelen van views:

  • Altijd realtime — er is geen verversingsvertraging, want er wordt niets vooraf berekend.
  • Geen extra opslag- of verversingskosten — je betaalt alleen compute op het moment dat iemand de view bevraagt.
  • Eenvoud — geen planning, geen onderhoud van een verversingsschema.

Nadelen van views:

  • Herhaalde berekening — een zware aggregatie over miljoenen rijen wordt bij élke query opnieuw uitgevoerd, ook als de onderliggende data niet is veranderd.
  • Traag bij complexe joins/aggregaties op grote datasets, zeker als meerdere views op elkaar worden gestapeld.
  • Onvoorspelbare compute-belasting — populaire dashboards die vaak dezelfde zware view bevragen, stapelen kosten op zonder dat je dat centraal kunt beheersen.

Materialized Views: een tussenweg

Snowflake kent ook MATERIALIZED VIEW: het resultaat wordt wél opgeslagen en Snowflake ververst het automatisch zodra de brondata wijzigt. Klinkt als een Dynamic Table, maar met belangrijke beperkingen:

  • Geen joins tussen meerdere tabellen — een materialized view mag maar van één brontabel afhangen.
  • Geen ORDER BY, beperkte aggregatiefuncties en geen subqueries.
  • Geen configureerbare verversingsfrequentie — Snowflake bepaalt zelf wanneer het ververst.

Voor eenvoudige "filter en aggregeer op één tabel"-scenario's is een materialized view prima. Zodra je moet joinen — en dat is in de praktijk bijna altijd — kom je uit bij een Dynamic Table.

Wat is een Dynamic Table?

Een Dynamic Table is een declaratief pipeline-object: je beschrijft de gewenste eindtoestand met een SELECT-statement — inclusief joins, aggregaties, window-functies — en Snowflake bouwt en onderhoudt automatisch de transformatielogica om het resultaat actueel te houden.

-- Dynamic Table: resultaat wordt opgeslagen en incrementeel ververst
CREATE OR REPLACE DYNAMIC TABLE analytics.dt_omzet_per_klant
    TARGET_LAG = '5 minutes'
    WAREHOUSE = TRANSFORM_WH
AS
SELECT
    k.klant_id,
    k.naam,
    SUM(o.bedrag) AS totale_omzet,
    COUNT(o.order_id) AS aantal_orders
FROM raw.klanten k
JOIN raw.orders o ON o.klant_id = k.klant_id
GROUP BY k.klant_id, k.naam;

De query is bijna identiek aan de view hierboven — het verschil zit in TARGET_LAG en WAREHOUSE. Snowflake plant zelf de verversingen zo in dat de data nooit meer dan 5 minuten achterloopt op de bron, en gebruikt daarvoor incrementele verwerking: alleen de rijen die zijn veranderd worden herberekend, niet de hele tabel.

TARGET_LAG in de praktijk

TARGET_LAG is geen harde garantie maar een doelstelling waar Snowflake naartoe plant. Je kunt ook TARGET_LAG = DOWNSTREAM instellen: dan erft de tabel de lag-eis van de Dynamic Tables die er weer bovenop zijn gebouwd, zodat je maar op één plek in de keten een expliciete eis hoeft te definiëren.

Kettens van Dynamic Tables

Dynamic Tables mogen op elkaar voortbouwen — een silver-laag Dynamic Table gebaseerd op een bronze-laag Dynamic Table, en een gold-laag erbovenop. Snowflake berekent automatisch de benodigde verversingsvolgorde en -frequentie van elke laag, vergelijkbaar met een DAG in Airflow of dbt — maar zonder dat je die orchestratie zelf hoeft te bouwen.

-- Silver: schoongemaakte events
CREATE OR REPLACE DYNAMIC TABLE silver.events_clean
    TARGET_LAG = '10 minutes'
    WAREHOUSE = TRANSFORM_WH
AS
SELECT event_id, event_type, user_id, event_ts
FROM bronze.events_raw
WHERE event_type IS NOT NULL;

-- Gold: erft de lag-eis van bovenliggende consumers
CREATE OR REPLACE DYNAMIC TABLE gold.events_per_user_dag
    TARGET_LAG = DOWNSTREAM
    WAREHOUSE = TRANSFORM_WH
AS
SELECT
    user_id,
    DATE_TRUNC('day', event_ts) AS dag,
    COUNT(*) AS aantal_events
FROM silver.events_clean
GROUP BY user_id, DATE_TRUNC('day', event_ts);

Refresh Mode: Incrementeel vs Volledig

Snowflake probeert een Dynamic Table standaard incrementeel te verversen: alleen de gewijzigde rijen in de brontabellen worden verwerkt, net als bij een MERGE in een handmatig gebouwde incremental load-pipeline. Niet elke query leent zich hiervoor — sommige constructies (bepaalde window-functies, non-deterministische functies, sommige outer joins) dwingen een volledige verversing af, waarbij de hele tabel opnieuw wordt berekend.

-- Refresh mode van een Dynamic Table controleren
SELECT refresh_mode, refresh_mode_reason
FROM TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
    NAME => 'analytics.dt_omzet_per_klant'
));

Dit is een belangrijk aandachtspunt bij ontwerp: een Dynamic Table die onbedoeld altijd volledig ververst, levert nauwelijks kostenvoordeel op ten opzichte van een geplande batch-job. Controleer refresh_mode_reason als de compute-kosten hoger uitvallen dan verwacht.

Views vs Materialized Views vs Dynamic Tables: Samengevat

Dimensie View Materialized View Dynamic Table
Opslag van resultaat Nee — altijd herberekend Ja Ja
Actualiteit Altijd realtime Automatisch, niet configureerbaar Configureerbaar via TARGET_LAG
Joins tussen tabellen Onbeperkt Niet toegestaan (één brontabel) Onbeperkt
Kosten in rust Geen Laag (incrementele verversing) Doorlopend — ververst ook zonder queries
Kosten bij veel queries Hoog — elke query herberekent Laag — leest opgeslagen resultaat Laag — leest opgeslagen resultaat
Kettens/lagen (bronze → silver → gold) Mogelijk, maar elke laag herberekent bij elke query Niet praktisch Native ondersteund, met afgeleide lag per laag
Onderhoud Geen Minimaal Warehouse-sizing en TARGET_LAG afstemmen

Welke Kies Je? Een Praktische Beslisboom

  • Data wordt zelden bevraagd, of moet altijd 100% realtime zijn? Kies een gewone view — geen verversingskosten, geen latency-afweging nodig.
  • Eenvoudige filter/aggregatie op precies één brontabel, met weinig eisen aan de verversingsfrequentie? Een materialized view volstaat en is het minst complex om te onderhouden.
  • Zware aggregatie of join die vaak wordt bevraagd (bijv. een dashboard dat elke minuut ververst) en waarbij een paar minuten latency acceptabel is? Kies een Dynamic Table — de compute-kosten verschuiven van "bij elke query" naar "bij elke verversing", wat bij veel lezers voordeliger is.
  • Meerlaagse transformatiepipeline (bronze → silver → gold) die je nu handmatig met taken of dbt orchestreert? Overweeg Dynamic Tables als vervanging — Snowflake regelt de afhankelijkheden en verversingsvolgorde automatisch.
  • Onvoorspelbaar of zeldzaam queryverkeer op een grote, dure aggregatie? Blijf bij een view. Een Dynamic Table die ververst zonder ooit bevraagd te worden, is pure verspilling.

Vuistregel

Begin met een view. Migreer naar een Dynamic Table zodra je merkt dat dezelfde zware query herhaaldelijk door meerdere consumers wordt uitgevoerd — dát is het punt waarop vooraf berekenen en incrementeel actueel houden goedkoper wordt dan telkens opnieuw berekenen.

Veelvoorkomende Valkuilen bij Dynamic Tables

Te agressieve TARGET_LAG

Een TARGET_LAG van '1 minute' op een zwaar getransformeerde tabel dwingt Snowflake tot frequente verversingen, ook als de brondata nauwelijks verandert. Stem de lag af op wat de consument daadwerkelijk nodig heeft — een dashboard dat elke 15 minuten wordt bekeken heeft geen lag van 1 minuut nodig.

Onbedoelde volledige verversing

Zoals eerder genoemd: bepaalde queryconstructies forceren een refresh_mode = FULL. Controleer dit bij het ontwerpen van de query — vaak is een kleine herformulering (bijvoorbeeld een deterministische functie in plaats van een non-deterministische) genoeg om incrementele verversing mogelijk te maken.

Verkeerde warehouse-sizing

Elke Dynamic Table draait verversingen op een gekoppeld warehouse. Een te klein warehouse verlengt de verversingstijd (en kan de TARGET_LAG-doelstelling laten missen); een te groot warehouse verspilt compute-budget bij kleine, frequente verversingen. Monitor via DYNAMIC_TABLE_REFRESH_HISTORY en pas de warehouse-grootte aan op basis van de daadwerkelijke verversingsduur.

Dynamic Tables als vervanging voor échte streaming

Een TARGET_LAG van enkele seconden is technisch mogelijk, maar in de praktijk kostbaar en meestal overkill. Voor écht near-realtime verwerking met sub-seconde latency is een streamingplatform zoals Apache Kafka gecombineerd met Snowpipe Streaming vaak een beter passende oplossing dan een Dynamic Table met een extreem lage lag.

Dynamic Tables en dbt

dbt ondersteunt Dynamic Tables als materialisatie op Snowflake: in plaats van materialized='table' of materialized='incremental' gebruik je materialized='dynamic_table' en configureer je target_lag en snowflake_warehouse in de modelconfiguratie.

-- models/omzet_per_klant.sql
{{
  config(
    materialized='dynamic_table',
    target_lag='5 minutes',
    snowflake_warehouse='TRANSFORM_WH'
  )
}}

SELECT
    k.klant_id,
    k.naam,
    SUM(o.bedrag) AS totale_omzet
FROM {{ ref('klanten') }} k
JOIN {{ ref('orders') }} o ON o.klant_id = k.klant_id
GROUP BY k.klant_id, k.naam;

Dit combineert het beste van beide werelden: dbt's versiebeheer, testing en documentatie, met de automatische incrementele verversing van Snowflake zelf — zonder dat je zelf is_incremental()-logica hoeft te schrijven zoals bij een klassiek incremental model.

Conclusie

Views, materialized views en Dynamic Tables zijn geen concurrenten maar drie punten op dezelfde schaal: van "altijd opnieuw berekenen, nooit vooraf opslaan" tot "automatisch en incrementeel actueel houden volgens een expliciete lag-doelstelling". De juiste keuze hangt af van hoe vaak data wordt bevraagd, hoe zwaar de transformatie is en hoeveel latency acceptabel is.

Dynamic Tables zijn met name waardevol zodra je meerdere transformatielagen handmatig orchestreert met taken of externe tools — Snowflake neemt die afhankelijkheidslogica dan grotendeels over, met minder onderhoud als resultaat.

Twijfel je of jouw Snowflake-views omgezet moeten worden naar Dynamic Tables, of wil je een bestaande transformatiepipeline herontwerpen? Neem contact op — ik denk graag mee. Zie ook Incremental Load vs Full Load voor de bredere afweging rond verversingsstrategieën en Snowflake DCM Projects voor hoe je deze objecten declaratief beheert.

Veelgestelde vragen

Wat is een Dynamic Table in Snowflake?

Een Dynamic Table is een Snowflake-object waarin je een query declareert en Snowflake automatisch en incrementeel de resultaten actueel houdt, op basis van een ingesteld TARGET_LAG. Het resultaat wordt fysiek opgeslagen in plaats van bij elke query herberekend.

Wat is het verschil tussen een Dynamic Table en een gewone view?

Een gewone view slaat geen data op — de query wordt bij elke SELECT opnieuw uitgevoerd. Een Dynamic Table slaat het resultaat op en houdt dat automatisch actueel volgens TARGET_LAG, waardoor query's sneller zijn maar de data nooit 100% realtime is.

Wat is het verschil tussen een Dynamic Table en een materialized view?

Een materialized view ondersteunt geen joins tussen meerdere brontabellen en heeft geen configureerbare verversingsfrequentie. Een Dynamic Table ondersteunt joins, aggregaties en kettens van Dynamic Tables, met een expliciet TARGET_LAG per object.

Wat is TARGET_LAG?

TARGET_LAG bepaalt hoe ver de data in een Dynamic Table maximaal mag achterlopen op de bron. Snowflake plant automatisch verversingen om aan deze doelstelling te voldoen, en berekent bij een keten van Dynamic Tables de benodigde frequentie van elke laag terug.

Kosten Dynamic Tables meer dan views?

Dynamic Tables verbruiken compute bij elke verversing, ook zonder queries. Views kosten alleen compute op het moment dat iemand ze bevraagt. Bij weinig queries op een grote dataset kan een view daarom goedkoper zijn; bij veel queries is een Dynamic Table vaak voordeliger.

Incremental vs Full Load Alle blogs