Entrepôt, Data Mart, Data Lake
Ce que ce chapitre apporte 5 points
- Opposer une charge transactionnelle et une charge analytique, et dire pourquoi elles ne cohabitent pas.
- Distinguer un fait d'une dimension, et construire un schéma en étoile.
- Choisir une granularité, et énoncer ce qu'elle interdit définitivement.
- Traiter le changement d'une dimension au cours du temps.
- Distinguer entrepôt, Data Mart et Data Lake, et organiser ce dernier en zones.
Une base transactionnelle est optimisée pour écrire beaucoup de petites choses très vite et sans jamais se tromper. Une analyse veut l'inverse : lire énormément, en une fois, sans rien écrire. Les deux charges s'excluent sur une même base, et la faire tenir les deux rôles à la fois est la cause la plus commune des lenteurs inexpliquées d'un système d'information.
Le modèle normalisé du parcours sur les bases de données a une qualité et un défaut, tous deux issus de la même propriété. Il élimine les redondances, donc chaque fait n'est écrit qu'une fois, donc une modification ne touche qu'un endroit : c'est exactement ce qu'il faut pour écrire. Mais alors chaque question un peu large exige de recoller une dizaine de tables, sur des millions de lignes, ce qui est exactement ce qu'il ne faut pas pour lire.
Ce chapitre construit le modèle inverse, celui des questions, et situe les deux organisations de stockage qui l'entourent.
Deux charges qui s'excluent
Une charge transactionnelle, dite OLTP, est faite de très nombreuses opérations courtes touchant peu de lignes chacune, en lecture comme en écriture, avec des exigences fortes de cohérence immédiate.
Une charge analytique, dite OLAP, est faite d'un petit nombre de requêtes qui balaient des millions de lignes, en lecture seule, et tolèrent des données vieilles de quelques heures.
| Transactionnel | Analytique | |
|---|---|---|
| Requêtes | des milliers par seconde | quelques dizaines par heure |
| Lignes touchées | une poignée | des millions |
| Colonnes lues | toutes celles de la ligne | trois ou quatre sur cinquante |
| Écritures | permanentes | par lots, ou aucune |
| Fraîcheur exigée | immédiate | la journée, souvent |
| Modèle adapté | normalisé | dimensionnel |
| Stockage adapté | par lignes | par colonnes |
Une requête analytique balaie des millions de lignes : elle accapare le processeur et les disques, et chasse de la mémoire cache les pages dont les opérations transactionnelles ont besoin. Celles-ci ne sont pas bloquées par des verrous : dans MySQL comme dans PostgreSQL, une lecture ordinaire travaille sur une photographie de la base et ne bloque aucune écriture (voir le chapitre sur les transactions). Elles attendent leur tour sur des ressources saturées, et le résultat est le même pour l'utilisateur.
Le symptôme est toujours le même : l'application ralentit à heures fixes, celles où quelqu'un actualise un tableau de bord. Le remède n'est pas d'optimiser la requête, mais de la déplacer sur une copie prévue pour cela.
C'est la première raison d'être d'un entrepôt : séparer physiquement les deux charges, avant même toute considération de modélisation.
Pourquoi ne pas lancer les analyses sur la base de production ?
Faits et dimensions
Un fait est un événement mesurable et daté : une vente, un passage, une mesure de capteur, une réservation ; ou l'état d'une chose relevé à date fixe, comme le solde d'un compte en fin de mois. La table de faits est longue et étroite, et ne fait que grandir.
Une mesure est une valeur numérique portée par le fait : un montant, une quantité, une durée, un solde. Les plus commodes s'additionnent, et ce n'est pas le cas de toutes.
Une dimension est un axe selon lequel on veut regarder les faits : le temps, le produit, le client, le lieu. La table de dimension est courte et large, et change peu.
Une mesure additive, comme un montant vendu, se somme selon toutes les dimensions.
Une mesure semi-additive, comme le solde d'un compte ou le nombre d'abonnés actifs relevé en fin de mois, se somme entre comptes à une même date, mais pas d'une date à l'autre : additionner les soldes de janvier, février et mars ne mesure rien. Dans le temps, on en lit le dernier relevé, ou la moyenne.
Une mesure non additive, comme un taux ou un prix unitaire, ne se somme dans aucune direction : on en stocke les composantes, et l'exercice 1 montre comment.
Les dimensions sont les mots qui suivent « par » dans la question. « Le chiffre d'affaires par mois par magasin par famille de produits » nomme la mesure puis trois dimensions. La phrase du métier donne le modèle presque littéralement, et c'est ce qui rend la modélisation dimensionnelle accessible sans formalisme.
L'exercice utile consiste à écrire les dix questions que le métier posera, à souligner les mesures et à entourer les mots qui suivent « par ». Les tables se déduisent ensuite.
1.Le solde de chaque compte est relevé à la fin de chaque mois. Que vaut la somme des soldes de janvier, février et mars d'un même compte ?
2.Comment reconnaître une dimension dans une demande métier ?
Le schéma en étoile
Un schéma en étoile place la table de faits au centre, entourée des tables de dimensions, chacune reliée par une clé étrangère unique. Aucune dimension n'en référence une autre.
clé primaire clé étrangère, avec la table visée
Le grain de cette table est la ligne de ticket : une ligne représente un produit, acheté en une certaine quantité, sur un ticket donné. numTicket n'a pas de table de dimension, puisqu'un ticket n'a pas d'autre attribut que son numéro : c'est une dimension dégénérée, et c'est elle qui permet de regrouper les lignes d'un même ticket pour calculer un panier ou chercher les produits achetés ensemble.
Trois traits distinguent ce schéma d'un modèle normalisé, et chacun est délibéré.
Les dimensions sont dénormalisées. famille et rayon restent dans Dim_Produit au lieu de vivre dans des tables séparées. La redondance est assumée : une dimension compte quelques milliers de lignes, la place ne coûte rien, et chaque table évitée est une jointure évitée.
La profondeur est de un. Toute question se répond avec la table de faits et les dimensions dont elle a besoin, jamais davantage. Le moteur n'a pas de choix difficile à faire, et les temps de réponse deviennent prévisibles.
Le temps est une table. Cela surprend, puisque toute base sait manipuler une date, et que le trimestre ou le numéro de semaine se calculent en une ligne. Mais jour férié, période de soldes ou exercice comptable ne se calculent pas, et sont exactement ce sur quoi le métier veut regrouper. La table garantit aussi qu'une seule définition circule : le 1er janvier 2027 tombe dans la semaine ISO 53 de l'année 2026, et deux requêtes qui calculent la semaine chacune à sa façon, l'une selon la norme ISO, l'autre en comptant depuis le 1er janvier, ne s'accordent pas.
Un schéma en flocon normalise les dimensions : Dim_Produit référence une table Famille, qui référence une table Rayon.
Le gain en place est négligeable, puisque les dimensions sont petites. Le coût est réel : une jointure de plus par niveau, et des requêtes que le métier ne sait plus écrire.
Le flocon se justifie dans deux cas seulement. Quand une hiérarchie est réellement partagée entre plusieurs dimensions, et quand un niveau porte beaucoup d'attributs propres qui n'ont rien à faire dans la dimension principale. Partout ailleurs, l'étoile gagne.
La granularité, décision irréversible
La granularité d'une table de faits est ce que représente exactement une de ses lignes : un article vendu, un ticket de caisse, un total quotidien par magasin.
Elle se déclare en une phrase, avant toute autre décision : « une ligne de cette table est... ». Si cette phrase ne se formule pas simplement, le modèle est faux.
Descendre d'un grain fin vers un grain grossier se fait par une somme. Remonter est impossible : rien dans un total quotidien ne permet de reconstituer les tickets.
Or les questions les plus intéressantes arrivent après, et personne ne les avait prévues. « Quels produits s'achètent ensemble » exige le grain de l'article ; conservé au grain du magasin, l'entrepôt ne répondra jamais, et il faudra attendre un an de nouvelles données pour commencer à répondre.
La règle est donc constante : conserver le grain le plus fin que le volume autorise, et construire les agrégats à côté, jamais à la place. Les agrégats se recalculent, le détail perdu ne revient pas.
1.Pourquoi dénormalise-t-on les dimensions dans un schéma en étoile ?
2.Une table de faits au grain du total quotidien par magasin ne porte que le chiffre d'affaires. Peut-on en tirer le panier moyen de l'an dernier ?
Le grain gouverne aussi les requêtes qui croisent deux tables de faits. « Le chiffre d'affaires de mars, le nombre de vendeurs et le chiffre d'affaires par vendeur, par région » réunit deux mesures relevées à deux grains différents : les ventes par magasin et par jour, l'effectif des vendeurs par magasin et par mois.
Une jointure apparie chaque ligne d'une table à toutes les lignes de l'autre qui partagent sa clé. Entre une table au jour et une table au mois, la ligne d'effectif de mars d'un magasin est donc recopiée une fois par jour de vente, et la somme des vendeurs compte chaque vendeur autant de fois que son magasin a eu de jours de vente. Aucune erreur ne s'affiche : la requête est valide, c'est son total qui est faux.
Quand les deux tables ont plusieurs lignes par clé, les deux totaux sont multipliés, chaque ligne de l'une comptant autant de fois que l'autre a de lignes pour sa clé. La parade ne change pas : ramener chaque table au même grain avant de les joindre, en agrégeant chacune de son côté, puis joindre une ligne à une ligne.
La jointure directe compte 18 vendeurs dans le Nord au lieu de 7, et 20 dans le Sud au lieu de 5 : chaque magasin y compte ses vendeurs une fois par jour de vente, quatre fois pour le magasin du Sud. Le chiffre d'affaires, lui, est juste, puisque chaque vente ne trouve qu'une ligne d'effectif ; c'est le rapport qui s'effondre, 300 par vendeur dans le Nord au lieu de 771,43. La correction agrège d'abord les ventes au magasin et au mois, ne garde que l'effectif de mars, et chaque magasin n'a plus qu'une ligne de chaque côté.
AND e.mois = substr(v.jour, 1, 7) : chaque vente trouve alors deux lignes d'effectif, février et mars, et le chiffre d'affaires double à son tour, 10 800 dans le Nord au lieu de 5 400, pour 36 vendeurs. Le chiffre d'affaires par vendeur du Nord reste à 300, puisque ses deux termes ont doublé ensemble : un rapport qui ne bouge pas ne dit rien de ses deux termes.
Quand une dimension change
Un client déménage, un produit change de famille, un magasin change de région. Que devient le passé ?
Deux traitements, et la question est métier avant d'être technique. Écraser. La dimension est mise à jour, l'ancienne valeur disparaît. Tout l'historique est alors relu avec la valeur actuelle : les ventes d'il y a trois ans apparaissent dans la nouvelle région du magasin. C'est ce qu'on veut pour corriger une faute de frappe, ou pour un attribut dont le passé n'intéresse personne. Le passé, lui, est perdu.
Historiser. Une nouvelle ligne de dimension est créée, avec une période de validité, et les faits antérieurs continuent de pointer vers l'ancienne. L'historique reste conforme à ce qui s'est réellement passé. C'est le traitement par défaut de toute dimension dont le passé compte. Historiser n'interdit pas pour autant la lecture actuelle : la ligne courante d'un client se retrouve par son code, et ses achats passés peuvent y être rattachés au moment de la requête. Une dimension historisée donne donc les deux lectures, une dimension écrasée n'en donne plus qu'une.
Le vocabulaire du domaine parle de dimensions à évolution lente. Écraser en est le type 1, historiser le type 2. Le type 3 ajoute une colonne qui garde l'ancienne valeur à côté de la nouvelle, regionPrecedente par exemple : les deux découpages se lisent, mais pour un seul changement à la fois.
La question à poser au métier est simple, et elle n'est pas technique : « quand ce client déménage, ses achats de l'an dernier appartiennent-ils à l'ancienne ville ou à la nouvelle ? » Les deux réponses sont défendables selon l'usage, et il faut choisir sciemment plutôt que de laisser l'outil décider.
clé primaire clé étrangère, avec la table visée
La clé primaire idClient est une clé de substitution, propre à l'entrepôt, distincte du codeClient du système source. C'est elle qui permet à deux versions d'un même client de coexister, chacune avec sa période de validité, et aux faits de désigner la bonne.
La requête suivante pose la dimension d'un magasin qui change de région, et en tire les deux lectures.
La première requête range les ventes de janvier du magasin M07 dans l'Est, où elles ont eu lieu ; la seconde passe par le code du magasin pour retrouver sa ligne courante, et range le même janvier dans le Nord. Les mêmes faits, la même dimension, deux réponses : c'est la question posée au métier, rendue visible.
UPDATE Dim_Magasin SET region = 'Nord' WHERE codeMagasin = 'M07';, qui écrase l'ancienne région du magasin. Les deux requêtes rendent alors le même résultat, 100 dans le Nord pour janvier : la lecture historique a disparu, et rien ne la fera revenir. Une dimension écrasée ne garde qu'une lecture.
Un client déménage. Qu'implique le choix d'historiser sa dimension ?
Data Mart et entrepôt
Un entrepôt de données est la copie, séparée des bases de production, où l'on rassemble les données de plusieurs sources pour l'analyse. La définition classique, due à Bill Inmon, lui prête quatre propriétés : il est organisé par sujets (le client, le produit) plutôt que par application ; intégré, un même client y portant un seul identifiant quelle que soit la source ; historisé, chaque donnée y étant datée ; non volatil, les données y étant chargées puis lues, et non modifiées au fil des opérations courantes.
Un Data Mart est un entrepôt restreint à un domaine métier : les ventes, la logistique, la qualité. Il contient les faits et les dimensions de ce domaine, et rien d'autre.
Deux façons de les articuler existent, et opposent deux écoles.
Construire d'abord l'entrepôt d'entreprise, normalisé et exhaustif, puis en dériver des Data Marts par domaine. La cohérence est garantie par construction ; la première livraison est lointaine. C'est l'approche descendante associée à Bill Inmon.
Construire d'abord les Data Marts, domaine par domaine, en imposant des dimensions conformes, c'est-à-dire partagées et identiques d'un mart à l'autre. La valeur arrive vite ; la cohérence repose sur une discipline. C'est l'approche ascendante associée à Ralph Kimball, d'où vient la modélisation dimensionnelle de ce chapitre.
Deux Data Marts construits séparément définissent chacun leur dimension « client », leur dimension « produit », et souvent leur notion de « mois ».
Les totaux ne se recoupent alors plus, personne ne sait lequel est juste, et la confiance dans l'entrepôt s'effondre. Une réunion entière peut se passer à comparer deux chiffres qui répondent en réalité à deux questions différentes.
Une dimension conforme, partagée par tous les marts, est ce qui rend les chiffres comparables. C'est une décision d'organisation autant que de technique, et c'est la partie difficile.
Le Data Lake
Un Data Lake conserve les données brutes, dans leur format d'origine, structurées ou non, sans schéma imposé à l'écriture. Le sens est donné à la lecture, par celui qui exploite.
L'entrepôt et le lac répondent à deux questions différentes. L'entrepôt répond vite et bien à des questions connues. Le lac garde de quoi répondre à des questions qui n'existent pas encore, y compris sur des données dont personne ne sait aujourd'hui quoi faire.
Déposer sans schéma ne veut pas dire déposer sans règle. Un lac où l'on écrit sans convention devient en deux ans un ensemble de fichiers dont personne ne sait ce qu'ils contiennent, d'où ils viennent, ni s'ils sont encore alimentés.
Trois disciplines l'évitent, et aucune n'est facultative.
Des zones. Une zone brute où rien n'est modifié, une zone raffinée où les données sont nettoyées et typées, une zone exploitable où elles sont modélisées pour l'usage. On ne saute pas de zone, et on ne remonte jamais.
Un catalogue. Chaque jeu déposé porte sa source, son propriétaire, sa fréquence de rafraîchissement, son schéma et son niveau de confidentialité. Sans catalogue, le lac n'est pas interrogeable, seulement stockable.
Un partitionnement lisible. Les fichiers rangés par date et par source, dans une arborescence stable, permettent de ne lire que ce qui est utile. C'est le sujet du chapitre sur l'optimisation.
Les deux organisations tendent aujourd'hui à se rejoindre : des formats de tables posés sur du stockage objet apportent au lac les transactions, l'évolution de schéma et l'historique qui manquaient, ce qu'on désigne parfois sous le nom de lakehouse. Le vocabulaire changera ; la distinction entre schéma à l'écriture et schéma à la lecture, elle, restera.
Qu'est-ce qui empêche un Data Lake de devenir un marécage ?
Mettre en pratique
La granularité d'une table de faits décide de son volume et de ce qu'elle interdit définitivement. Les deux se calculent avant de charger la première ligne.
Dimensionner un schéma en étoile
- 1.
Un million de commandes comportent en moyenne 4 lignes chacune. Combien de lignes la table de faits contient-elle si le grain est la ligne de commande ?
- 2.
Combien en contiendrait-elle si le grain était la commande entière ?
- 3.
Une dimension temps couvre 10 ans au grain du jour, dont trois années bissextiles. Combien de lignes contient-elle ?
- 4.
Le temps couvre 3 653 jours, et l'entrepôt compte 500 produits, 200 magasins et 50 clients types. Le cube croise toutes les valeurs de ces quatre dimensions, une case par combinaison. Combien de cases compterait-il ?
Ce croisement de toutes les valeurs de toutes les dimensions s'appelle un cube : chaque case porte l'agrégat des faits qui y tombent, et c'est sur lui que se pensent les mouvements de l'analyse OLAP que décrit le chapitre sur l'interrogation. La dernière réponse, plus de dix-huit milliards de cases, dit pourquoi un cube n'est jamais matérialisé en entier. La quasi-totalité de ces croisements ne correspond à aucune vente, et l'entrepôt ne stocke que les faits qui ont réellement eu lieu. C'est la différence entre l'espace des combinaisons possibles et l'espace des observations.
La règle est donc de charger au grain le plus FIN dont on dispose, quitte à agréger ensuite. Agréger se fait à volonté ; désagréger ne se fait jamais.
Un service veut analyser « le taux de retour par fournisseur et par mois ». Quels faits, quelles dimensions, quelle mesure ?
Le mot qui suit « par » donne les dimensions : fournisseur et temps.
La mesure est plus subtile. Un taux n'est pas additif : la moyenne de deux taux n'est pas le taux global, exactement comme au chapitre sur le découpage. Il ne faut donc pas stocker le taux, mais ses deux composantes, le nombre de retours et le nombre d'articles livrés, et calculer le rapport à la lecture.
Le fait est la livraison d'un article, avec un indicateur de retour, ou plus simplement deux tables de faits, livraisons et retours, partageant les mêmes dimensions conformes.
C'est la règle générale : stocker ce qui s'additionne, calculer le reste à la lecture.
Une table de faits est au grain du total quotidien par magasin, et ne porte que le chiffre d'affaires. Le métier demande le panier moyen. Que répondre ?
Que c'est impossible pour le passé avec ce qui est stocké, et que cela le restera.
Le panier moyen est le chiffre d'affaires divisé par le nombre de tickets. Le nombre de tickets n'est pas dans la table, et rien ne permet de le reconstituer à partir d'un total.
Deux issues. Ajouter dès maintenant une mesure « nombre de tickets » à la table existante, ce qui répondra à partir d'aujourd'hui mais pas pour le passé. Ou reprendre l'alimentation à un grain plus fin, si les données sources sont encore disponibles, ce qui n'est pas garanti.
C'est l'illustration exacte du caractère irréversible de l'agrégation.
Un magasin passe de la région Est à la région Nord en mars. Le chiffre d'affaires de janvier doit-il apparaître dans l'Est ou dans le Nord ?
Les deux réponses sont défendables, et la question est métier.
Pour un suivi de performance des équipes régionales, janvier appartient à l'Est : c'est cette équipe qui a réalisé la vente. Cela impose d'historiser la dimension, avec deux lignes de magasin et des périodes de validité.
Pour un pilotage de l'organisation actuelle, janvier doit apparaître dans le Nord, afin que les totaux correspondent au découpage d'aujourd'hui. Écraser y conduit, mais historiser aussi : la ligne courante du magasin se retrouve par son code, et les faits de janvier s'y rattachent à la lecture, comme le montre la requête de la section sur les dimensions qui changent.
L'erreur n'est pas de choisir l'une ou l'autre lecture, mais de ne pas choisir, et de découvrir le comportement obtenu en constatant un écart inexpliqué dans un tableau de bord. Dans le doute, historiser est le choix qui ne ferme rien : une dimension écrasée ne rend jamais le passé.
Une équipe propose de remplacer l'entrepôt par un Data Lake, « puisque tout y est ». Que manque-t-il ?
Trois choses, dont deux ne s'obtiennent pas par la technique.
Le modèle. Le lac contient les données brutes, pas les faits et dimensions. Chaque analyste devra reconstruire les jointures et les règles de gestion, différemment, et les chiffres ne se recouperont pas.
Les définitions partagées. « Client actif », « chiffre d'affaires net », « mois » sont des conventions qui doivent exister à un seul endroit. L'entrepôt est cet endroit.
Le temps de réponse. Un balayage de fichiers bruts ne répond pas en deux secondes à un tableau de bord interrogé par cent personnes.
Le lac et l'entrepôt ne s'opposent pas : le lac alimente l'entrepôt, et garde ce dont l'entrepôt n'a pas encore l'usage.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Le grain qui ne se remonte pas, et la jointure que le flocon ajoute par niveau.
- Une jointure de plus par niveauNiveau 2
- La zone du lacNiveau 2
- Le grain qu'on ne remonte pasNiveau 3
- Historiser ou écraserNiveau 3