Une application enregistre des commandes, un CRM des contacts, un outil marketing des campagnes. Pour répondre à « quel canal rapporte le plus de clients fidèles ? », il faut réunir ces données au même endroit, les historiser et les rendre faciles à interroger, sans ralentir les bases de production. C’est le rôle de la plateforme de données analytique. Ce cours vous apprend à la modéliser ; cette première leçon pose le vocabulaire.
L’entrepôt de données
Un entrepôt de données (data warehouse) est une base conçue pour l’analyse. Les données y sont structurées (tables et colonnes typées), intégrées (un client a le même identifiant quelle que soit la source), historisées (on garde les états passés) et organisées pour des requêtes d’agrégation sur de gros volumes. Exemples de produits : BigQuery, Snowflake, Amazon Redshift, Azure Synapse, ou PostgreSQL pour des volumes modestes. La plupart stockent les données en colonnes : une requête qui lit trois colonnes d’une table de cinquante ne lit que ces trois colonnes.
Le schéma y est appliqué à l’écriture (schema on write) : une donnée qui ne respecte pas le type attendu est refusée au chargement.
Le lac de données
Un lac de données (data lake) est un stockage de fichiers à faible coût, souvent un stockage objet (Amazon S3, Azure Data Lake Storage, Google Cloud Storage). On y dépose tout, tel quel : exports CSV, événements JSON, fichiers Parquet, images, journaux. Le schéma est appliqué à la lecture (schema on read) : c’est le moteur de requête (Spark, Trino, etc.) qui interprète les fichiers.
Avantage : on garde tout, à bas coût, y compris ce dont on ne connaît pas encore l’usage. Risque : sans catalogue ni règles, le lac devient un « marécage » où personne ne sait quels fichiers sont fiables.
Le lakehouse
Le lakehouse combine les deux : les données restent dans des fichiers ouverts (souvent Parquet) sur un stockage objet, mais un format de table (Delta Lake, Apache Iceberg, Apache Hudi) ajoute par-dessus ce qui manquait au lac : transactions, schéma contrôlé, mises à jour et suppressions de lignes, historique des versions. Plusieurs moteurs peuvent lire les mêmes tables.
| Entrepôt | Lac | Lakehouse | |
|---|---|---|---|
| Données | structurées | tout format | structurées et semi-structurées |
| Schéma | à l’écriture | à la lecture | contrôlé par le format de table |
| Interrogation | SQL | moteurs variés | SQL et moteurs variés |
Le choix dépend des volumes, des usages (rapports, science des données) et des compétences de l’équipe ; la modélisation que vous allez apprendre est la même dans les trois cas.
ETL ou ELT
Historiquement, on extrayait, transformait sur un serveur dédié, puis chargeait le résultat (ETL). Avec des entrepôts puissants et facturés à l’usage, on fait plutôt de l’ELT : on charge d’abord les données brutes, puis on les transforme dans l’entrepôt, en SQL. Des outils comme dbt (cours DE2) organisent ces transformations.
L’architecture en couches
Les transformations sont rangées en couches successives. Les noms varient selon les équipes :
- Brute (bronze, raw) : copie fidèle des sources, horodatée, jamais modifiée. On peut toujours tout recalculer à partir d’elle.
- Nettoyée (silver, staging) : types corrects, noms de colonnes harmonisés, valeurs normalisées, doublons de chargement supprimés. Une table par source, sans logique métier.
- Métier (gold, marts) : modèles prêts à l’analyse, typiquement des schémas en étoile, avec les règles de gestion (« une commande annulée ne compte pas dans le chiffre d’affaires »).
Voici une transformation typique de la couche brute vers la couche nettoyée. La source est chargée plusieurs fois par jour : une même commande peut apparaître dans deux chargements ; on garde la version la plus récente.
WITH classees AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY _loaded_at DESC) AS rang
FROM raw_commandes
)
SELECT CAST(id AS INTEGER) AS commande_id,
lower(trim(client)) AS client,
CAST(montant AS REAL) AS montant,
upper(devise) AS devise
FROM classees
WHERE rang = 1;
Remarquez que la couche nettoyée ne filtre pas les lignes incomplètes (un montant absent reste NULL) : elle les rend visibles. Décider qu’une commande sans montant est exclue d’un indicateur est une règle métier, qui appartient à la couche suivante.
Exercices
Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.
De la couche brute à la couche nettoyée
Table brute :
raw_commandes(id, client, montant, devise, _loaded_at), toutes les colonnes en texte ;_loaded_atest l’horodatage du chargement.Écrivez la requête de la couche nettoyée. Pour chaque
id, gardez uniquement le chargement le plus récent, et produisez :commande_id: l’id en entier ;client: le nom sans espaces autour, en minuscules ;montant: le montant en nombre réel (laissez NULL s’il est absent) ;devise: la devise en majuscules.
Données de l'exercice (SQL)
-- Couche brute (bronze) : chargée deux fois par jour, sans transformation CREATE TABLE raw_commandes (id TEXT, client TEXT, montant TEXT, devise TEXT, _loaded_at TEXT); INSERT INTO raw_commandes VALUES ('1', ' amina ', '49.90', 'EUR', '2026-03-01 02:00'), ('2', 'BASTIEN', '120', 'eur', '2026-03-01 02:00'), ('2', 'BASTIEN', '125', 'eur', '2026-03-02 02:00'), ('3', 'Camille', '15.5', 'EUR', '2026-03-01 02:00'), ('4', 'camille', NULL, 'EUR', '2026-03-02 02:00');WITH classees AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) AS rang FROM raw_commandes ) SELECT ... FROM classees WHERE rang = 1;Contrôle de volumétrie entre couches
Table brute :
raw_commandes(id, client, montant, devise, _loaded_at), toutes les colonnes en texte ;_loaded_atest l’horodatage du chargement.Avant de publier la couche nettoyée, on vérifie la volumétrie. Affichez en une ligne le nombre de lignes brutes (alias
lignes_brutes) et le nombre de commandes distinctes (aliascommandes).Données de l'exercice (SQL)
-- Couche brute (bronze) : chargée deux fois par jour, sans transformation CREATE TABLE raw_commandes (id TEXT, client TEXT, montant TEXT, devise TEXT, _loaded_at TEXT); INSERT INTO raw_commandes VALUES ('1', ' amina ', '49.90', 'EUR', '2026-03-01 02:00'), ('2', 'BASTIEN', '120', 'eur', '2026-03-01 02:00'), ('2', 'BASTIEN', '125', 'eur', '2026-03-02 02:00'), ('3', 'Camille', '15.5', 'EUR', '2026-03-01 02:00'), ('4', 'camille', NULL, 'EUR', '2026-03-02 02:00');SELECT COUNT(*) AS lignes_brutes, ... AS commandes FROM raw_commandes;Choisir une architecture
Une équipe veut conserver à bas coût des journaux JSON et des images de produits, tout en offrant des tables SQL fiables, avec mises à jour de lignes, aux analystes. Quelle architecture répond le mieux ?
- Un entrepôt de données classique uniquement
- Un lakehouse : fichiers ouverts sur stockage objet avec un format de table comme Delta Lake ou Iceberg
- Un simple dossier partagé de fichiers CSV
Quiz de fin de leçon
Que signifie « schema on read » ?
- Le schéma est vérifié au chargement
- Le schéma est appliqué par le moteur au moment de la lecture des fichiers
- Les données n'ont jamais de schéma
Dans quelle couche place-t-on la règle « une commande annulée ne compte pas dans le chiffre d’affaires » ?
- Brute
- Nettoyée
- Métier
Pourquoi ne modifie-t-on jamais la couche brute ?
- Parce que c'est interdit par SQL
- Pour pouvoir rejouer toutes les transformations depuis les données d'origine
- Pour économiser de l'espace
Qu’est-ce qui caractérise l’ELT ?
- Les données sont transformées avant d'être chargées
- Les données brutes sont chargées puis transformées dans l'entrepôt
- Les données ne sont jamais transformées
La suite du cours
- Construire un modèle en étoile en SQL20 min
- Dimensions à évolution lente (SCD)20 min
- Partitionnement, clustering et tables d'agrégats18 min
- Maîtriser les coûts d'un entrepôt16 min