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

Datawarehouse Opzetten

Van architectuurkeuze tot productie: een complete handleiding voor het ontwerpen en bouwen van een schaalbaar, performant datawarehouse op moderne cloud platforms.

SQL Azure Snowflake Databricks ETL/ELT Gratis
1

Architectuurkeuze

Cloud vs on-prem, platforms vergelijken, kosten inschatten

De keuze voor je datawarehouse platform bepaalt je kosten, schaalbaarheid en onderhoudslasten voor jaren. Cloud-native platforms zijn voor de meeste organisaties de beste keuze.

PlatformTypeSterk inKosten model
SnowflakeCloud SaaSMulti-cloud, eenvoud, data sharingPay-per-second compute
Azure SynapseCloud PaaSAzure integratie, hybrideDWU of serverless
DatabricksCloud PaaSBig data, ML, streamingDBU per cluster
BigQueryCloud SaaSGoogle ecosystem, serverlessPay-per-query of flat rate
SQL ServerOn-prem/CloudBestaande MS licentiesLicentie + hardware

Beslissingscriteria

  • Datavolume: < 100 GB → eenvoud prioriteit; > 1 TB → schaalbaarheid prioriteit
  • Concurrente gebruikers: Snowflake en Synapse schalen goed horizontaal
  • Bestaande cloud: Azure-shop → Synapse/Databricks; Google-shop → BigQuery
  • ML/AI workloads: Databricks is de sterkste keuze
  • Compliance: Data residency vereisten kunnen de cloud-keuze beperken
ℹ️ Voor startende organisaties: begin met Snowflake (eenvoudig te beheren, uitstekende documentatie) of Azure Synapse serverless (geen kosten voor opslag die je al in ADLS hebt).
2

Lagenmodel (Bronze / Silver / Gold)

Medallion architecture, databewegingen, verantwoordelijkheden

Het Medallion-architectuurpatroon organiseert data in drie lagen met toenemende kwaliteit en transformatiegraad. Dit is de industriestandaard voor moderne datawarehouses.

LaagAliasInhoudWie schrijft
BronzeRaw / LandingRuwe brondata, exact zoals ontvangenIngest pipeline
SilverClean / CuratedGecleand, gevalideerd, verrijktdbt / Spark
GoldServing / MartBusiness-ready, geaggregeerddbt / SQL

Bronze laag principes

  • Data nooit verwijderen — append-only of versioned
  • Voeg technische metadata toe: _ingested_at, _source_file, _batch_id
  • Sla op in Parquet of Delta Lake formaat (niet CSV)
  • Geen business logica — puur opslag
sql — bronze tabel aanmaken (databricks/delta)
CREATE TABLE IF NOT EXISTS bronze.orders_raw ( order_id STRING, customer_id STRING, order_date STRING, -- ruwe data: altijd STRING in bronze amount STRING, status STRING, _ingested_at TIMESTAMP DEFAULT current_timestamp(), _source_file STRING, _batch_id STRING ) USING DELTA PARTITIONED BY (date_trunc('day', _ingested_at)) LOCATION 'abfss://bronze@storage.dfs.core.windows.net/orders/';

Silver laag — type casting en validatie

sql — silver transformatie
INSERT INTO silver.orders SELECT order_id, customer_id, CAST(order_date AS DATE) AS order_date, CAST(amount AS DECIMAL(18,2)) AS amount, LOWER(status) AS status, _ingested_at, current_timestamp() AS _transformed_at FROM bronze.orders_raw WHERE order_id IS NOT NULL -- validatie AND amount ~ '^[0-9]+(\.[0-9]+)?$' -- numeriek check AND _ingested_at > ( SELECT MAX(_ingested_at) FROM silver.orders ); -- incrementeel laden
3

Schema ontwerp

Naming conventions, datatypes, DDL best practices

Consistente naamgeving en juiste datatypes voorkomen verwarring en zorgen voor optimale query performance.

Naming conventions

ElementConventieVoorbeeld
Schemasnake_case, enkelvoudbronze, silver, gold, mart_sales
Feitentabelfct_ prefixfct_orders, fct_revenue
Dimensietabeldim_ prefixdim_customer, dim_product
Stagingstg_ prefixstg_salesforce_orders
Primary keytabel_idorder_id, customer_id
Foreign keydim_tabel_idcustomer_id, product_id
Datum kolom_at (timestamp), _date (date)created_at, order_date
Booleanis_ prefixis_active, is_deleted

Datatypes correct gebruiken

sql — ddl best practices
CREATE TABLE dim_customer ( customer_sk INTEGER NOT NULL, -- surrogate key: integer customer_id VARCHAR(50) NOT NULL, -- business key: string customer_name VARCHAR(200) NOT NULL, email VARCHAR(254), -- max email lengte country_code CHAR(2), -- ISO 3166-1: altijd 2 tekens annual_revenue DECIMAL(18, 2), -- geld: nooit FLOAT customer_tier VARCHAR(20) CHECK (customer_tier IN ('bronze', 'silver', 'gold')), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP, valid_from DATE NOT NULL, -- SCD2 valid_to DATE, -- NULL = huidig actief record CONSTRAINT pk_dim_customer PRIMARY KEY (customer_sk) );
⚠️ Gebruik nooit FLOAT of DOUBLE voor geldbedragen — floating point geeft afrondingsfouten. Gebruik altijd DECIMAL(p, s) of NUMERIC(p, s).
4

Ster-schema vs Sneeuwvlokschema

Kimball methodologie, denormalisatie, query performance

In een datawarehouse kies je tussen twee schema ontwerpen. Voor de meeste BI-toepassingen is het ster-schema de beste keuze.

EigenschapSter-schemaSneeuwvlokschema
StructuurDimensies gedenormaliseerdDimensies genormaliseerd (3NF)
Joins voor queryWeinig (1 niveau)Meer (meerdere niveaus)
Query performanceSnellerLangzamer
OpslagruimteMeer (redundantie)Minder
OnderhoudEenvoudigerComplexer
GebruikBI/rapportageOLTP-achtige situaties

Ster-schema voorbeeld

sql — ster-schema feitentabel
CREATE TABLE fct_orders ( -- Surrogate keys (foreign keys naar dimensies) date_sk INTEGER NOT NULL REFERENCES dim_date(date_sk), customer_sk INTEGER NOT NULL REFERENCES dim_customer(customer_sk), product_sk INTEGER NOT NULL REFERENCES dim_product(product_sk), channel_sk INTEGER NOT NULL REFERENCES dim_channel(channel_sk), -- Business key (voor traceerbaarheid) order_id VARCHAR(50) NOT NULL, -- Feiten (meetbare waarden) quantity INTEGER NOT NULL, unit_price DECIMAL(18,2) NOT NULL, discount_amount DECIMAL(18,2) DEFAULT 0, revenue DECIMAL(18,2) NOT NULL, cost DECIMAL(18,2), CONSTRAINT pk_fct_orders PRIMARY KEY (order_id) );
5

ETL vs ELT aanpak

Extract-Transform-Load vs Extract-Load-Transform

De keuze tussen ETL en ELT bepaalt waar je transformatielogica plaatst en welke tools je gebruikt.

AspectETLELT
TransformatieBuiten het warehouse (ETL tool)Binnen het warehouse (SQL/dbt)
ToolsSSIS, Informatica, Talenddbt, Spark, BigQuery scripting
SchaalbaarheidBeperkt door ETL serverSchaalt mee met warehouse
KostenLicentiekosten ETL toolWarehouse compute kosten
WanneerComplexe transformaties, legacyCloud DWH, moderne aanpak
Voor nieuwe projecten is ELT de aanbevolen aanpak: laad ruwe data in de Bronze laag, transformeer binnen het warehouse met dbt of Spark. Dit is goedkoper, schaalbaarder en eenvoudiger te debuggen.
6

Partitionering & Clustering

Snowflake clustering keys, Databricks partitions, pruning

Partitionering en clustering zorgen ervoor dat queries alleen relevante data lezen (partition pruning / cluster pruning), wat enorm scheelt in scankosten en snelheid.

Partitionering in Databricks (Delta Lake)

sql — databricks delta partitionering
-- Partitioneer feitentabellen op datum CREATE TABLE fct_orders USING DELTA PARTITIONED BY (order_year INT, order_month INT) AS SELECT *, YEAR(order_date) AS order_year, MONTH(order_date) AS order_month FROM silver.orders; -- Z-ORDER clustering voor snellere point queries OPTIMIZE fct_orders ZORDER BY (customer_id, product_id); -- Vacuum (verwijder oude Delta bestanden) VACUUM fct_orders RETAIN 168 HOURS; -- 7 dagen history

Clustering in Snowflake

sql — snowflake clustering
-- Clustering key instellen ALTER TABLE fct_orders CLUSTER BY (order_date, customer_id); -- Clustering status controleren SELECT SYSTEM$CLUSTERING_INFORMATION('fct_orders'); -- Handmatige recluster (bij grote wijzigingen) ALTER TABLE fct_orders RECLUSTER;
⚠️ Snowflake: Partitioneer niet handmatig — Snowflake doet dit automatisch via Micro-partitions. Gebruik clustering keys alleen voor tabellen > 1 TB die frequent op specifieke kolommen worden gefilterd.
7

Performance tips

Materialisatie, caching, query optimalisatie, statistieken

Query optimalisatie technieken

sql — efficiënte aggregatie
-- Slecht: subquery die per rij wordt uitgevoerd SELECT customer_id, (SELECT COUNT(*) FROM fct_orders o2 WHERE o2.customer_id = o1.customer_id) AS order_count FROM dim_customer o1; -- Goed: window function of join met aggregatie SELECT c.customer_id, COALESCE(o.order_count, 0) AS order_count FROM dim_customer c LEFT JOIN ( SELECT customer_id, COUNT(*) AS order_count FROM fct_orders GROUP BY customer_id ) o ON c.customer_id = o.customer_id; -- Window function: running total per klant SELECT customer_id, order_date, amount, SUM(amount) OVER ( PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cumulative_revenue FROM fct_orders;

Statistieken bijhouden (Synapse/PostgreSQL)

sql — statistieken updaten
-- Azure Synapse: statistieken handmatig updaten UPDATE STATISTICS fct_orders (order_date) WITH FULLSCAN; UPDATE STATISTICS fct_orders (customer_id) WITH SAMPLE 30 PERCENT; -- PostgreSQL: automatisch (maar handmatig forceren na bulk load) ANALYZE fct_orders; VACUUM ANALYZE fct_orders;
Materialiseer tussenresultaten als je complexe CTE-ketens hebt die meerdere keren worden hergebruikt. In Snowflake: gebruik een tijdelijke tabel. In Databricks: gebruik CACHE TABLE of Delta Live Tables.
8

Monitoring & Datakwaliteit

Query logs, alerting, datakwaliteitscontroles, SLA tracking

Een goed datawarehouse heeft monitoring voor zowel technische performance als datakwaliteit. Slechte data die ongedetecteerd blijft schaadt vertrouwen in alle downstream rapportages.

Datakwaliteitscontroles

sql — datakwaliteit checks
-- 1. Volledigheid: controleer verwacht aantal rijen SELECT DATE_TRUNC('day', order_date) AS dag, COUNT(*) AS aantal_orders, SUM(amount) AS totaal_omzet FROM fct_orders WHERE order_date >= CURRENT_DATE - INTERVAL '7 days' GROUP BY 1 ORDER BY 1 DESC; -- 2. Uniciteit: geen dubbele primaire sleutels SELECT order_id, COUNT(*) AS duplicaten FROM fct_orders GROUP BY order_id HAVING COUNT(*) > 1; -- 3. Referentiële integriteit SELECT COUNT(*) AS orphaned_orders FROM fct_orders o LEFT JOIN dim_customer c ON o.customer_sk = c.customer_sk WHERE c.customer_sk IS NULL; -- 4. Freshness: data niet ouder dan 26 uur SELECT MAX(_ingested_at) AS laatste_ingest, DATEDIFF('hour', MAX(_ingested_at), CURRENT_TIMESTAMP()) AS uren_geleden, CASE WHEN DATEDIFF('hour', MAX(_ingested_at), CURRENT_TIMESTAMP()) > 26 THEN 'ALERT: data te oud' ELSE 'OK' END AS status FROM fct_orders;
ℹ️ Overweeg Great Expectations (Python), dbt tests of Soda Core voor geautomatiseerde datakwaliteitscontroles. Koppel alerts aan Slack of Teams via webhooks zodat het team direct op de hoogte is.
9

Checklist

Controleer voor go-live
Architectuur & Ontwerp
  • Platform gekozen en geconfigureerd
  • Bronze/Silver/Gold lagen aangemaakt
  • Naming conventions gedocumenteerd en gevolgd
  • Ster-schema geïmplementeerd in Gold laag
Data Kwaliteit
  • Null checks op verplichte kolommen
  • Uniciteitscontroles op primaire sleutels
  • Referentiële integriteitscontroles
  • Freshness monitoring actief
Performance
  • Partitionering op datum kolommen
  • Clustering keys ingesteld voor grote tabellen
  • Statistieken actueel na bulk loads
  • Query performance getest met realistische data
Beveiliging
  • Role-based access control geconfigureerd
  • PII data gemaskeerd of beperkt toegankelijk
  • Audit logging actief
  • Netwerktoegang beperkt (VNet/Private Endpoint)