OLTP vs OLAP et stockage en colonnes

Résumé

Une base transactionnelle (OLTP) sert une application : beaucoup de petites lectures et écritures sur quelques lignes à la fois. Une base analytique (OLAP) sert des questions : peu de requêtes, chacune lit beaucoup de lignes mais peu de colonnes. Ces deux charges favorisent deux dispositions physiques opposées. Le stockage en lignes garde tous les champs d’une ligne côte à côte, ce qui convient à la recherche d’un enregistrement. Le stockage en colonnes garde chaque colonne séparément, ce qui convient à l’agrégation sur des millions de lignes. Beaucoup d’erreurs de coût ou de performance en analytique viennent d’avoir oublié cette différence.

Prérequis

Savoir ce qu’est une table et une requête d’agrégation (SUM, GROUP BY). Aucune autre note n’est nécessaire.

Deux charges de travail

OLTP (online transaction processing)OLAP (online analytical processing)
Question type« Quel est le solde du compte 4217 ? »« Quel est le chiffre d’affaires par région et par mois sur trois ans ? »
Lignes touchées par requêteUne ou quelques-unesDes millions
Colonnes luesPresque toutesQuelques-unes
ÉcrituresFréquentes, petites, transactionnellesChargements par lots, ou flux
Garantie attendueTransactions fiables : ACID vs BASECohérence d’un instantané lisible
Modèle de donnéesNormalisé : Normalisation 2NF et 3NFSouvent dénormalisé ou dimensionnel : Inmon, Kimball et Data Vault
ExemplesPostgreSQL, MySQL, Oracle (usage applicatif)BigQuery, Snowflake, ClickHouse, DuckDB

Les deux charges se mélangent mal sur le même système : une grosse agrégation bloque des transactions courtes, et un modèle normalisé multiplie les jointures coûteuses pour l’analyse. D’où la séparation habituelle : la base applicative alimente un entrepôt analytique (voir Staging, ODS, DWH et architecture médaillon).

Lignes ou colonnes

Prenons une table de commandes de 100 millions de lignes et 20 colonnes, que l’on suppose de 8 octets chacune pour simplifier.

flowchart LR
    subgraph L["Stockage en lignes"]
      L1["ligne 1 : id, date, client, montant, …"]
      L2["ligne 2 : id, date, client, montant, …"]
      L3["ligne 3 : …"]
    end
    subgraph C["Stockage en colonnes"]
      C1["colonne id : 1, 2, 3, …"]
      C2["colonne date : …"]
      C3["colonne montant : 12, 40, 7, …"]
    end
RequêteStockage en lignesStockage en colonnes
SELECT * FROM commandes WHERE id = 4217Une lecture : tous les champs de la ligne sont contigusIl faut recomposer la ligne à partir de 20 colonnes
SELECT SUM(montant) FROM commandesLit chaque ligne en entier : 100 M × 20 × 8 octets, soit environ 16 GoLit la seule colonne montant : 100 M × 8 octets, soit environ 0,8 Go

Les 16 Go et 0,8 Go sont un calcul illustratif sans compression ; l’ordre de grandeur (un facteur de l’ordre du nombre de colonnes) est ce qu’il faut retenir.

La documentation de BigQuery décrit la même idée : les bases en lignes sont efficaces pour retrouver un enregistrement, mais moins pour des fonctions analytiques sur beaucoup d’enregistrements, parce qu’il faut lire tous les champs. BigQuery stocke chaque colonne séparément, ce qui l’avantage pour parcourir une colonne sur tout un jeu de données.1

Deux autres effets du stockage en colonnes

  • Meilleure compression. Les valeurs d’une même colonne se ressemblent plus que les valeurs d’une même ligne. Des techniques comme l’encodage par plages (run-length encoding) en profitent, ce qui réduit les octets lus.1
  • Statistiques par colonne. Un format colonnaire peut garder des valeurs minimale et maximale par column chunk, ce qui permet de sauter des blocs entiers. Voir Parquet, le format de fichier colonnaire.

Ce que ça change en pratique

Règles qui en découlent

  • Éviter SELECT * sur un moteur colonnaire. Chaque colonne ajoutée à la requête ajoute des octets lus, et sur BigQuery en mode à la demande, des octets facturés.
  • Filtrer sur la partition quand la table est partitionnée : on lit moins de blocs.
  • Ne pas utiliser un entrepôt comme base applicative. Chercher une ligne par identifiant ou mettre à jour une ligne à la fois est le cas défavorable du stockage en colonnes.
  • Interroger une table « large » (beaucoup de colonnes) n’est pas un problème en colonnes tant que la requête n’en lit que quelques-unes. Voir Union all vs unpivot pour un cas où cette nuance compte.

Ce n'est pas binaire

Des systèmes hybrides existent (stockage mixte, ou deux copies de la donnée, une par charge). Les limites évoluent ; vérifier ce que fait réellement le produit utilisé plutôt que de se fier à son étiquette.

Notes liées

Notes de bas de page

  1. Overview of BigQuery storage, section « Storage layout », documentation Google Cloud consultée le 24 octobre 2026. ↩ ↩2