← Terug naar Downloads DataPartner365 — datapartner365.nl
DataPartner365 · Handleiding · 2026

Handleiding: Data Vault 2.0 Implementeren

Van Raw Vault tot Business Vault — bouw een schaalbare, auditeerbare data architectuur met Hub, Link en Satellite tabellen, dbt integratie en bewezen loading patterns.

Data Vault 2.0 SQL dbt Agile Gratis
1

Wat is Data Vault 2.0?

Geschiedenis, filosofie en core componenten

Data Vault 2.0 is een modelleringsmethodologie ontwikkeld door Dan Linstedt in de jaren 90, formeel gepubliceerd in 2000 en uitgebreid naar versie 2.0 in 2013. De methodologie combineert elementen van derde normaalvorm (3NF) en ster-schema's om een flexibele, auditeerbare en schaalbare data architectuur te creëren voor enterprise data warehouses.

De filosofie van Data Vault is gebaseerd op drie kernprincipes: agility (bronwijzigingen veroorzaken minimale impact), auditability (elke record is volledig herleidbaar naar de bron) en scalability (parallelle loading zonder bottlenecks).

Vergelijking met andere modelleringsbenaderingen

Kenmerk3NF (Inmon)Ster-schema (Kimball)Data Vault 2.0
Primair doelOLTP, integratieRapportage, analyseEnterprise DWH, staging
HistoriekopslagBeperktVia SCDIngebouwd (altijd insert)
Flexibiliteit bij bronwijzigingenLaagGemiddeldHoog
AuditeerbaarheidGemiddeldLaagVolledig
LeercurveLaagLaagHoog
Queryperformance directMatigHoogLaag (via Information Mart)

Wanneer kies je voor Data Vault?

  • Je hebt 10+ bronsystemen die je moet integreren
  • Bronsystemen wijzigen regelmatig (nieuwe kolommen, gewijzigde logica)
  • Je hebt strikte audit- en compliance-eisen (GDPR, SOX, AVG)
  • Je werkt in een Agile team dat iteratief delivered
  • Je wil volledige historiek van alle data bijhouden

Core componenten van de Data Vault architectuur

LaagDoelInhoud
Raw VaultAs-is opslag van bronsystemenHubs, Links, Satellites — ongewijzigde brondata
Business VaultBerekende en afgeleide dataComputed Satellites, Derived Links, Same-As Links
Information MartRapportage en analyseSter-schema's, flat tables, views voor BI tools
Data Vault is het meest waardevol in enterprise omgevingen met veel bronsystemen en frequente wijzigingen. Voor kleinere projecten met een beperkt aantal bronnen is een Kimball ster-schema doorgaans eenvoudiger en sneller te implementeren.
2

De drie basisentiteiten

Hub, Link, Satellite — structuur en SQL voorbeelden

Data Vault bestaat uit drie fundamentele entiteittypes. Elke tabel heeft een specifiek doel en een vaste structuur. Het begrijpen van deze drie typen is de basis van elke Data Vault implementatie.

Hub — business sleutels

Een Hub slaat de unieke business sleutels op van een kernentiteit (bijv. Klant, Product, Order). Een Hub bevat géén beschrijvende attributen — alleen de business key en metadata. Elke business key komt precies één keer voor in de Hub.

KolomTypeVerplichtBeschrijving
klant_hkCHAR(32)VERPLICHTHash key — MD5/SHA hash van de business key
klant_bkVARCHAR(255)VERPLICHTBusiness key uit het bronsysteem
load_dtsTIMESTAMPVERPLICHTLaadtijdstip — wanneer de record voor het eerst gezien
rec_srcVARCHAR(100)VERPLICHTRecord source — welk bronsysteem de data leverde
sql — hub_klant ddl
-- Hub: unieke business sleutels voor Klant
CREATE TABLE raw_vault.hub_klant (
    klant_hk        CHAR(32)      NOT NULL,   -- MD5 hash van klant_bk
    klant_bk        VARCHAR(255)  NOT NULL,   -- bijv. 'KLANT-00123'
    load_dts        TIMESTAMP     NOT NULL,   -- eerste keer gezien
    rec_src         VARCHAR(100)  NOT NULL,   -- bijv. 'CRM_SALESFORCE'
    CONSTRAINT pk_hub_klant PRIMARY KEY (klant_hk)
);

-- Insert: alleen nieuwe business keys laden
INSERT INTO raw_vault.hub_klant (klant_hk, klant_bk, load_dts, rec_src)
SELECT DISTINCT
    MD5(UPPER(TRIM(klant_id)))  AS klant_hk,
    klant_id                    AS klant_bk,
    CURRENT_TIMESTAMP           AS load_dts,
    'CRM_SALESFORCE'            AS rec_src
FROM staging.stg_klant
WHERE NOT EXISTS (
    SELECT 1 FROM raw_vault.hub_klant h
    WHERE h.klant_hk = MD5(UPPER(TRIM(stg_klant.klant_id)))
);

Link — relaties tussen Hubs

Een Link legt de relatie vast tussen twee of meer Hubs. Links zijn immutable: eens aangemaakt worden ze nooit gewijzigd. Een Link bevat de hash keys van de betrokken Hubs en metadata.

sql — link_bestelling_klant ddl
-- Link: relatie tussen Bestelling en Klant
CREATE TABLE raw_vault.lnk_bestelling_klant (
    bestelling_klant_hk  CHAR(32)     NOT NULL,  -- hash van bestelling_hk + klant_hk
    bestelling_hk        CHAR(32)     NOT NULL,  -- FK naar hub_bestelling
    klant_hk             CHAR(32)     NOT NULL,  -- FK naar hub_klant
    load_dts             TIMESTAMP    NOT NULL,
    rec_src              VARCHAR(100) NOT NULL,
    CONSTRAINT pk_lnk_bestelling_klant PRIMARY KEY (bestelling_klant_hk),
    CONSTRAINT fk_lnk_bk_bestelling FOREIGN KEY (bestelling_hk)
        REFERENCES raw_vault.hub_bestelling(bestelling_hk),
    CONSTRAINT fk_lnk_bk_klant FOREIGN KEY (klant_hk)
        REFERENCES raw_vault.hub_klant(klant_hk)
);

-- Hash key berekening: concatenatie van betrokken hub keys
SELECT
    MD5(bestelling_hk || '|' || klant_hk) AS bestelling_klant_hk
FROM staging.stg_bestelling;

Satellite — beschrijvende attributen

Een Satellite slaat alle beschrijvende attributen op van een Hub of Link, inclusief volledige historiek. Elke wijziging in attributen leidt tot een nieuwe rij (insert-only). De hash_diff kolom detecteert of een record daadwerkelijk gewijzigd is.

sql — sat_klant_details ddl
-- Satellite: attributen van Klant met volledige historiek CREATE TABLE raw_vault.sat_klant_details ( klant_hk CHAR(32) NOT NULL, -- FK naar hub_klant load_dts TIMESTAMP NOT NULL, -- tijdstip van deze versie load_end_dts TIMESTAMP, -- NULL = huidig record hash_diff CHAR(32) NOT NULL, -- hash van alle attributen rec_src VARCHAR(100) NOT NULL, -- Business attributen klant_naam VARCHAR(200), email VARCHAR(254), telefoonnummer VARCHAR(20), segment VARCHAR(50), stad VARCHAR(100), land CHAR(2), CONSTRAINT pk_sat_klant_details PRIMARY KEY (klant_hk, load_dts), CONSTRAINT fk_sat_kd_klant FOREIGN KEY (klant_hk) REFERENCES raw_vault.hub_klant(klant_hk) ); -- Hash diff: detecteer wijzigingen (laad alleen als hash_diff verschilt) INSERT INTO raw_vault.sat_klant_details SELECT MD5(UPPER(TRIM(klant_id))) AS klant_hk, CURRENT_TIMESTAMP AS load_dts, NULL AS load_end_dts, MD5(klant_naam || email || segment || stad) AS hash_diff, 'CRM_SALESFORCE' AS rec_src, klant_naam, email, telefoonnummer, segment, stad, land FROM staging.stg_klant s WHERE NOT EXISTS ( SELECT 1 FROM raw_vault.sat_klant_details sat WHERE sat.klant_hk = MD5(UPPER(TRIM(s.klant_id))) AND sat.hash_diff = MD5(s.klant_naam || s.email || s.segment || s.stad) AND sat.load_end_dts IS NULL );

Point-in-Time (PIT) tabellen

Een PIT-tabel is een hulpstructuur die de meest recente Satellite records op elk gewenst tijdstip bijhoudt. PIT tabellen verbeteren de queryperformance enorm bij het samenvoegen van meerdere Satellites.

sql — pit_klant structuur
-- Point-in-Time tabel voor Klant CREATE TABLE raw_vault.pit_klant ( klant_hk CHAR(32) NOT NULL, snapshot_dts TIMESTAMP NOT NULL, -- het peilmoment sat_klant_details_dts TIMESTAMP, -- actuele load_dts in SAT_KLANT_DETAILS sat_klant_contact_dts TIMESTAMP, -- actuele load_dts in SAT_KLANT_CONTACT CONSTRAINT pk_pit_klant PRIMARY KEY (klant_hk, snapshot_dts) );
ℹ️ PIT tabellen worden typisch dagelijks of per batch opgebouwd. Ze zijn optioneel maar sterk aanbevolen zodra je meerdere Satellites per Hub hebt. Zonder PIT tabel vereist elke query complexe lateral joins of correlated subqueries.
3

Naming Conventions & Standaarden

Prefix conventies, hash keys, DDL standaarden

Consistente naamgeving is in Data Vault extra belangrijk omdat de architectuur veel tabellen genereert. Stel conventies vast voordat het project start en documenteer ze in een Data Dictionary.

Prefix conventies

PrefixTypeVoorbeeld
HUB_Hub tabelHUB_KLANT, HUB_PRODUCT, HUB_ORDER
LNK_Link tabelLNK_BESTELLING_KLANT, LNK_ORDER_PRODUCT
SAT_Satellite tabelSAT_KLANT_DETAILS, SAT_KLANT_CONTACT
PIT_Point-in-Time tabelPIT_KLANT, PIT_PRODUCT
BV_Business Vault objectBV_SAT_KLANT_SCORE, BV_LNK_KLANT_MERGED
SAL_Same-As LinkSAL_KLANT_DEDUPLICATIE
EFF_Effectivity SatelliteEFF_LNK_BESTELLING_KLANT
STG_Staging tabelSTG_KLANT, STG_ORDER

Hash key berekening

Hash keys worden berekend uit de genormaliseerde business key. De keuze van het hash-algoritme heeft impact op performance en botsingsrisico.

AlgoritmeOutputBotsingsrisicoPerformanceAanbeveling
MD532 hex charsTheoretisch (verwaarloosbaar)SnelGeschikt voor de meeste projecten
SHA-140 hex charsLaagGemiddeldVerouderd, vermijd voor nieuw werk
SHA-25664 hex charsExtreem laagLangzamerBij hoge compliance-eisen
sql — hash key standaardisatie
-- Regel 1: Trim spaties, uppercase, NULL behandeling MD5(UPPER(TRIM(COALESCE(klant_id, '-1')))) -- Regel 2: Samengestelde sleutels — gebruik scheidingsteken MD5( UPPER(TRIM(land_code)) || '||' || UPPER(TRIM(klant_id)) ) -- Regel 3: Hash diff voor Satellites MD5( COALESCE(klant_naam, '') || '||' || COALESCE(email, '') || '||' || COALESCE(segment, '') || '||' || COALESCE(stad, '') ) -- Alternatief met SHA-256 (PostgreSQL) ENCODE(SHA256(CONVERT_TO(UPPER(TRIM(klant_id)), 'UTF8')), 'hex')

Verplichte metadata kolommen

KolomTypeAanwezig inBeschrijving
load_dtsTIMESTAMP NOT NULLHub, Link, SatelliteTijdstip van eerste/huidige load
load_end_dtsTIMESTAMP NULLSatelliteEindtijdstip versie; NULL = huidig
rec_srcVARCHAR(100) NOT NULLHub, Link, SatelliteBronsysteem identificatie
hash_diffCHAR(32) NOT NULLSatelliteHash van alle attributen, voor change detectie
tenant_idVARCHAR(50)Alle tabellenMulti-tenant ondersteuning (optioneel)
⚠️ Nooit NULL in hash keys! Gebruik altijd een standaardwaarde (bijv. '-1' of 'UNKNOWN') als de business key NULL kan zijn. Een NULL in een hash key zorgt voor niet-aaneensluitende records in de Hub en onvindbare Links.
4

Raw Vault vs Business Vault

As-is opslag, berekende data, Same-As Links en Effectivity Satellites

De scheiding tussen Raw Vault en Business Vault is een van de meest belangrijke architectuurprincipes van Data Vault 2.0. Deze scheiding garandeert dat de originele brondata altijd ongewijzigd toegankelijk blijft.

Raw Vault — as-is data opslag

De Raw Vault slaat brondata op precies zoals ontvangen van het bronsysteem. Geen transformaties, geen interpretaties, geen businessregels. Elke record is volledig herleidbaar tot een specifieke load uit een specifiek bronsysteem.

  • Alleen insert operaties — nooit update of delete
  • Data wordt opgeslagen in de originele structuur (wel genormaliseerd naar Hub/Link/Sat)
  • Bevat alle historiek zonder interpretatie
  • Is de single source of truth voor audit en compliance

Business Vault — computed en afgeleide data

De Business Vault bevat data die is afgeleid uit de Raw Vault via businessregels en berekeningen. Business Vault objecten zijn duidelijk gelabeld (prefix BV_) en altijd reproduceerbaar vanuit de Raw Vault.

sql — business vault computed satellite
-- Computed Satellite: klant klantwaarde score berekend vanuit Raw Vault CREATE TABLE business_vault.bv_sat_klant_score ( klant_hk CHAR(32) NOT NULL, load_dts TIMESTAMP NOT NULL, load_end_dts TIMESTAMP, hash_diff CHAR(32) NOT NULL, rec_src VARCHAR(100) NOT NULL DEFAULT 'BUSINESS_RULE_KLANT_SCORE', -- Berekende attributen klant_score DECIMAL(5,2), klant_tier VARCHAR(20), -- 'BRONZE', 'SILVER', 'GOLD', 'PLATINUM' score_versie VARCHAR(10) DEFAULT 'v2.1', CONSTRAINT pk_bv_sat_klant_score PRIMARY KEY (klant_hk, load_dts) ); -- Vul Business Vault met berekende score op basis van omzetdata INSERT INTO business_vault.bv_sat_klant_score SELECT h.klant_hk, CURRENT_TIMESTAMP AS load_dts, NULL AS load_end_dts, MD5(CAST(SUM(f.omzet) AS VARCHAR)) AS hash_diff, 'BUSINESS_RULE_KLANT_SCORE' AS rec_src, ROUND(SUM(f.omzet) / 1000.0, 2) AS klant_score, CASE WHEN SUM(f.omzet) > 100000 THEN 'PLATINUM' WHEN SUM(f.omzet) > 50000 THEN 'GOLD' WHEN SUM(f.omzet) > 10000 THEN 'SILVER' ELSE 'BRONZE' END AS klant_tier, 'v2.1' AS score_versie FROM raw_vault.hub_klant h JOIN raw_vault.lnk_bestelling_klant lbk ON h.klant_hk = lbk.klant_hk JOIN raw_vault.sat_bestelling_financieel f ON lbk.bestelling_hk = f.bestelling_hk WHERE f.load_end_dts IS NULL GROUP BY h.klant_hk;

Same-As Links (SAL)

Een Same-As Link legt vast dat twee business keys in de Hub dezelfde echte entiteit vertegenwoordigen. Dit is de Data Vault manier voor deduplicatie en entiteitsresolutie — zonder de Raw Vault aan te passen.

sql — same-as link deduplicatie
-- SAL: twee klant records die dezelfde persoon zijn CREATE TABLE business_vault.sal_klant_dedup ( sal_hk CHAR(32) NOT NULL, -- hash van master_hk + duplicate_hk master_klant_hk CHAR(32) NOT NULL, -- de 'winnende' Hub record dupl_klant_hk CHAR(32) NOT NULL, -- de duplicaat Hub record load_dts TIMESTAMP NOT NULL, rec_src VARCHAR(100) NOT NULL, -- bijv. 'MDM_DEDUP_PROCESS' match_methode VARCHAR(50), -- 'FUZZY_NAME', 'EMAIL_MATCH', etc. match_score DECIMAL(5,4), CONSTRAINT pk_sal_klant_dedup PRIMARY KEY (sal_hk) );

Effectivity Satellites

Een Effectivity Satellite houdt bij wanneer een Link-relatie actief of inactief is. Dit is nodig omdat Links zelf immutable zijn — je verwijdert een Link nooit, maar registreert de inactiviteit in een aparte Satellite.

sql — effectivity satellite
-- Effectivity Satellite: is de klant-bestelling relatie nog actief? CREATE TABLE raw_vault.eff_lnk_bestelling_klant ( bestelling_klant_hk CHAR(32) NOT NULL, -- FK naar lnk_bestelling_klant load_dts TIMESTAMP NOT NULL, load_end_dts TIMESTAMP, rec_src VARCHAR(100) NOT NULL, is_actief BOOLEAN NOT NULL DEFAULT TRUE, CONSTRAINT pk_eff_lnk_bk PRIMARY KEY (bestelling_klant_hk, load_dts) );
Houd de Business Vault gescheiden van de Raw Vault in aparte schema's (raw_vault en business_vault). Zo is altijd duidelijk welke data ongewijzigde brondata is en welke data via businessregels is berekend.
5

Implementatie met dbt

dbt projectstructuur, macro's, incrementeel laden en testing

dbt (data build tool) is de standaard tool voor het bouwen van Data Vault pipelines in moderne data stacks. dbt biedt versiebeheert SQL transformaties, maakt testen eenvoudig en ondersteunt incrementeel laden out-of-the-box.

dbt projectstructuur voor Data Vault

bash — aanbevolen mapstructuur
dbt_project/ ├── models/ │ ├── staging/ # Staging laag — brondata normaliseren │ │ ├── crm/ │ │ │ ├── stg_klant.sql │ │ │ └── stg_bestelling.sql │ │ └── erp/ │ │ └── stg_factuur.sql │ ├── raw_vault/ # Raw Vault — Hubs, Links, Satellites │ │ ├── hubs/ │ │ │ ├── hub_klant.sql │ │ │ └── hub_product.sql │ │ ├── links/ │ │ │ └── lnk_bestelling_klant.sql │ │ └── satellites/ │ │ ├── sat_klant_details.sql │ │ └── sat_klant_contact.sql │ ├── business_vault/ # Business Vault — berekende objecten │ │ ├── bv_sat_klant_score.sql │ │ └── sal_klant_dedup.sql │ └── information_mart/ # Informatiemarts — ster-schema voor BI │ ├── dim_klant.sql │ └── fct_omzet.sql ├── macros/ │ ├── hash_key.sql # Hash key berekening macro │ └── hash_diff.sql # Hash diff berekening macro └── tests/ ├── generic/ └── singular/

Macro's voor hash keys

jinja/sql — macros/hash_key.sql
{% macro hash_key(columns, alias='hash_key') %} {#- Berekent MD5 hash van één of meer kolommen -#} MD5( {% for col in columns %} UPPER(TRIM(COALESCE({{ col }}::VARCHAR, '-1'))) {% if not loop.last %} || '||' || {% endif %} {% endfor %} ) AS {{ alias }} {% endmacro %} {% macro hash_diff(columns, alias='hash_diff') %} {#- Berekent MD5 hash van alle Satellite attributen -#} MD5( {% for col in columns %} COALESCE({{ col }}::VARCHAR, '') {% if not loop.last %} || '||' || {% endif %} {% endfor %} ) AS {{ alias }} {% endmacro %}

Incrementeel laden met dbt

sql — models/raw_vault/hubs/hub_klant.sql
{{ config( materialized = 'incremental', unique_key = 'klant_hk', schema = 'raw_vault' ) }} WITH source AS ( SELECT * FROM {{ ref('stg_klant') }} {% if is_incremental() %} -- Alleen nieuwe records laden bij incrementele runs WHERE _loaded_at > (SELECT MAX(load_dts) FROM {{ this }}) {% endif %} ), hub AS ( SELECT {{ hash_key(['klant_id'], 'klant_hk') }}, klant_id AS klant_bk, CURRENT_TIMESTAMP AS load_dts, rec_src FROM source QUALIFY ROW_NUMBER() OVER (PARTITION BY klant_id ORDER BY _loaded_at) = 1 ) SELECT * FROM hub
sql — models/raw_vault/satellites/sat_klant_details.sql
{{ config( materialized = 'incremental', unique_key = ['klant_hk', 'load_dts'], schema = 'raw_vault' ) }} WITH source AS ( SELECT {{ hash_key(['klant_id'], 'klant_hk') }}, {{ hash_diff(['klant_naam', 'email', 'segment', 'stad']) }}, CURRENT_TIMESTAMP AS load_dts, NULL AS load_end_dts, rec_src, klant_naam, email, telefoonnummer, segment, stad, land FROM {{ ref('stg_klant') }} {% if is_incremental() %} WHERE _loaded_at > (SELECT MAX(load_dts) FROM {{ this }}) {% endif %} ), -- Verwijder records waarbij hash_diff niet is gewijzigd gefilterd AS ( SELECT s.* FROM source s {% if is_incremental() %} LEFT JOIN {{ this }} t ON s.klant_hk = t.klant_hk AND t.load_end_dts IS NULL WHERE t.hash_diff IS NULL -- nieuw record OR s.hash_diff != t.hash_diff -- gewijzigd record {% endif %} ) SELECT * FROM gefilterd

Testing met dbt

yaml — models/raw_vault/schema.yml
version: 2 models: - name: hub_klant description: "Hub met unieke business sleutels voor Klant" columns: - name: klant_hk description: "MD5 hash van klant_bk" tests: - unique - not_null - name: klant_bk tests: - not_null - name: load_dts tests: - not_null - name: rec_src tests: - not_null - name: sat_klant_details columns: - name: klant_hk tests: - not_null - relationships: to: ref('hub_klant') field: klant_hk - name: hash_diff tests: - not_null
ℹ️ Overweeg het dbt-datavault4dbt pakket (open source) voor kant-en-klare Data Vault macro's. Dit pakket biedt generieke Hub, Link en Satellite templates die je kunt aanpassen voor je specifieke project.
6

Loading Patterns

Full load, incrementeel, parallel loading en idempotentie

Data Vault is ontworpen voor hoge-performante, parallelle loading. De juiste loading strategie is cruciaal voor schaalbaarheid en betrouwbaarheid van je pipeline.

Full load vs incrementeel

StrategieWanneer gebruikenVoordelenNadelen
Full loadInitiële load, kleine bronsystemenEenvoudig, geen change detection nodigTraag bij grote datasets
Incrementeel (timestamp)Bronsysteem heeft updated_at kolomSnel, efficiëntLate arriving data gemist
Incrementeel (CDC)Hoge frequentie, near-real-timeMinimale latency, volledigComplexe setup (Debezium, Fivetran)
Hash vergelijkingGeen timestamp beschikbaarDetecteert elke wijzigingVolledig scan vereist

Parallel loading strategie

Een van de grootste voordelen van Data Vault is de mogelijkheid om Hubs, Links en Satellites parallel te laden. De volgorde is echter wel van belang vanwege foreign key afhankelijkheden.

yaml — loading volgorde en parallelisme
# Fase 1: Staging (parallel per bron) staging: - stg_klant # CRM bron - stg_bestelling # Orders bron - stg_product # ERP bron # Fase 2: Hubs (alle hubs parallel) hubs: - hub_klant ↗ parallel - hub_bestelling ↗ parallel - hub_product ↗ parallel # Fase 3: Links (na Hubs — parallel onderling) links: - lnk_bestelling_klant ↗ parallel - lnk_bestelling_product ↗ parallel # Fase 4: Satellites (parallel na Hubs en Links) satellites: - sat_klant_details ↗ parallel - sat_klant_contact ↗ parallel - sat_bestelling_status ↗ parallel

Idempotentie waarborgen

Een Data Vault pipeline moet idempotent zijn: meerdere keren draaien met dezelfde brondata produceert altijd hetzelfde resultaat. Dit maakt herverwerking en foutenherstel veilig.

sql — idempotente hub insert
-- MERGE patroon (Snowflake/SQL Server/BigQuery) MERGE INTO raw_vault.hub_klant AS target USING ( SELECT DISTINCT MD5(UPPER(TRIM(klant_id))) AS klant_hk, klant_id AS klant_bk, CURRENT_TIMESTAMP AS load_dts, rec_src FROM staging.stg_klant ) AS source ON target.klant_hk = source.klant_hk WHEN NOT MATCHED THEN INSERT (klant_hk, klant_bk, load_dts, rec_src) VALUES (source.klant_hk, source.klant_bk, source.load_dts, source.rec_src); -- WHEN MATCHED: niets doen — Hub records zijn immutable! -- INSERT ... ON CONFLICT patroon (PostgreSQL) INSERT INTO raw_vault.hub_klant (klant_hk, klant_bk, load_dts, rec_src) SELECT DISTINCT MD5(UPPER(TRIM(klant_id))), klant_id, CURRENT_TIMESTAMP, rec_src FROM staging.stg_klant ON CONFLICT (klant_hk) DO NOTHING; -- Hub is immutable

Error handling en auditability

  • Sla elke load run op in een audit tabel (load_audit) met tijdstip, aantal records, status
  • Gebruik een error Satellite (SAT_ERR_) voor records die niet geladen konden worden
  • Log de rec_src altijd granulaar genoeg om terug te herleiden welke batch welke records bevatte
  • Bewaar staging tabellen tot de load succesvol is geverifieerd
⚠️ Late arriving data: Data Vault kan goed omgaan met laat arriverende records. Een Hub record kan altijd worden toegevoegd met een historische load_dts, en de bijbehorende Satellites volgen automatisch. Pas wel op met PIT tabellen — die moeten gerecalculeerd worden na een late load.
7

Van Data Vault naar Information Mart

Ster-schema genereren, Bridge tables, Dimensional modelling

De Data Vault zelf is niet direct geschikt voor rapportage — de complexe joins en historische structuur maken queries traag en moeilijk. De Information Mart is de rapportagelaag die gebouwd wordt bovenop de Data Vault, typisch als ster-schema of flat table.

Ster-schema genereren vanuit Data Vault

Een dimensietabel in de Information Mart wordt gebouwd door de Hub samen te voegen met de meest recente Satellite records (via PIT tabel of directe join op load_end_dts IS NULL).

sql — dim_klant vanuit data vault
-- Dimensietabel: actuele klantgegevens (SCD Type 1 snapshot) CREATE OR REPLACE VIEW information_mart.dim_klant AS SELECT h.klant_hk AS klant_sk, -- surrogate key h.klant_bk AS klant_id, -- business key d.klant_naam, d.email, d.segment, d.stad, d.land, c.telefoonnummer, s.klant_score, s.klant_tier, h.load_dts AS eerste_gezien, d.load_dts AS details_bijgewerkt FROM raw_vault.hub_klant h -- Meest recente klantdetails LEFT JOIN raw_vault.sat_klant_details d ON d.klant_hk = h.klant_hk AND d.load_end_dts IS NULL -- Meest recente contactgegevens LEFT JOIN raw_vault.sat_klant_contact c ON c.klant_hk = h.klant_hk AND c.load_end_dts IS NULL -- Berekende scores vanuit Business Vault LEFT JOIN business_vault.bv_sat_klant_score s ON s.klant_hk = h.klant_hk AND s.load_end_dts IS NULL;

Bridge tables

Een Bridge table is een precomputed join van meerdere Links en Hubs. Bridge tables maken complexe veel-op-veel relaties efficiënt querybaar vanuit de Information Mart zonder de volledige Data Vault structuur te doorlopen.

sql — bridge table klant-product via bestellingen
-- Bridge: klant → bestelling → product (voor omzetanalyse) CREATE TABLE information_mart.brg_klant_product ( snapshot_dts DATE NOT NULL, klant_hk CHAR(32) NOT NULL, bestelling_hk CHAR(32) NOT NULL, product_hk CHAR(32) NOT NULL, -- Gedriligeerde metrics voor snelle rapportage omzet DECIMAL(12,2), aantal INTEGER, CONSTRAINT pk_brg_klant_product PRIMARY KEY (snapshot_dts, klant_hk, bestelling_hk, product_hk) ); -- Vul Bridge table dagelijks INSERT INTO information_mart.brg_klant_product SELECT CURRENT_DATE AS snapshot_dts, lbk.klant_hk, lbk.bestelling_hk, lbp.product_hk, SUM(sbr.omzet) AS omzet, SUM(sbr.aantal) AS aantal FROM raw_vault.lnk_bestelling_klant lbk JOIN raw_vault.lnk_bestelling_product lbp ON lbk.bestelling_hk = lbp.bestelling_hk JOIN raw_vault.sat_bestelling_regel sbr ON sbr.bestelling_product_hk = lbp.bestelling_product_hk AND sbr.load_end_dts IS NULL GROUP BY lbk.klant_hk, lbk.bestelling_hk, lbp.product_hk;

Dimensional modelling bovenop Data Vault

De Information Mart volgt het Kimball ster-schema principe. Dimensies en feitentabellen worden gegenereerd vanuit de Data Vault objecten. Gebruikers van BI-tools (Power BI, Tableau, Looker) werken uitsluitend met de Information Mart — nooit direct met de Raw of Business Vault.

Data Vault objectInformation Mart objectTransformatie
Hub + actuele SatellitesDimensietabel (dim_)JOIN + SCD Type 1 of 2
Link + metrische SatellitesFeitentabel (fct_)JOIN + aggregatie
Bridge tableFeitentabel (fct_)Directe mapping
PIT tabel + SatellitesHistorische dimensieSnapshot per datum
Business Vault SatellitesBerekende dimensiekolommenDirecte overname
Gebruik dbt marts als de uiteindelijke transformatielaag voor je Information Mart. Maak de marts zo simpel mogelijk — complexe joins en businesslogica horen thuis in de Business Vault, niet in de mart-laag. Zo blijven marts snel te begrijpen en te onderhouden.
8

Checklist

Controleer je Data Vault implementatie
Architectuur & Ontwerp
  • Raw Vault, Business Vault en Information Mart zijn in aparte schema's
  • Elke Hub bevat slechts één business key type
  • Links bevatten geen descriptieve attributen (die horen in Satellites)
  • Prefix conventies zijn consistent: HUB_, LNK_, SAT_, PIT_, BV_, SAL_
Hash Keys & Metadata
  • Hash keys gebruiken genormaliseerde input (UPPER, TRIM, COALESCE)
  • Scheidingsteken in samengestelde hash keys is consistent (||)
  • Alle tabellen bevatten load_dts en rec_src
  • Satellites bevatten hash_diff voor change detectie
Loading & Idempotentie
  • Pipeline is idempotent — meerdere runs met dezelfde data geven zelfde resultaat
  • Hubs en Links worden geladen vóór Satellites
  • Alle inserts zijn insert-only (geen updates in Raw Vault)
  • Elke load run wordt geregistreerd in een audit tabel
dbt & Testing
  • Hub hash keys zijn getest op uniqueness en not_null
  • Satellite foreign keys zijn getest via dbt relationships test
  • Incrementele modellen zijn getest met een volledige herrun
  • Macro's voor hash_key en hash_diff zijn gecentraliseerd
Information Mart
  • Marts zijn gebaseerd op PIT tabellen of load_end_dts IS NULL joins
  • Business-gebruikers hebben alleen toegang tot de Information Mart
  • Bridge tables zijn aangemaakt voor complexe veel-op-veel rapportage
  • Data lineage is gedocumenteerd: van bronsysteem tot mart kolom