data / sql
Réplication et partitionnement (niveau expert)
Explication
Ce que vous allez apprendre
- Distinguer le rôle du partitionnement (une table divisée sur UN serveur) de la réplication (copies sur PLUSIEURS serveurs)
- Choisir entre partitionnement par plage, par liste et par hachage selon les données
- Comprendre le "partition pruning" qui accélère les requêtes filtrées
- Suivre le décalage (lag) d'une réplication en streaming PostgreSQL
- Distinguer le partitionnement du sharding, une distribution réellement multi-serveurs
Dans quel contexte ?
Une plateforme SaaS voit sa table commandes dépasser 300 millions de lignes, avec des requêtes qui ne filtrent presque toujours que sur les derniers mois. Découper cette table en partitions mensuelles (commandes_2024, commandes_2025) permet à une requête sur juin 2025 de n'examiner qu'une seule sous-table, au lieu des trois années entières - exactement la logique du "partition pruning" détaillée ici.
D'abord, le problème d'une table qui grossit trop
Une table de plusieurs centaines de millions de lignes pose deux problèmes distincts. Les requêtes deviennent lentes même avec de bons index. Et un seul serveur physique finit par atteindre ses limites de capacité.
Deux réponses différentes à ces deux problèmes
Le partitionnement répond au premier problème, la réplication répond au second. Voyons-les l'un après l'autre.
Le partitionnement : découper une table en tiroirs
Le partitionnement divise UNE table en plusieurs sous-tables physiques, tout en restant sur le MÊME serveur, comme un grand meuble à tiroirs où chaque tiroir contient les données d'une période ou d'une catégorie.
Trois façons de répartir les données entre les tiroirs
On peut partitionner par plage (les commandes de 2024 dans un tiroir, celles de 2025 dans un autre), par liste (les clients français dans un tiroir, les belges dans un autre), ou par hachage (une répartition équilibrée sans logique métier particulière).
| Stratégie | Base de répartition | Exemple |
|---|---|---|
RANGE | Intervalle de valeurs | commandes par année (cree_le) |
LIST | Valeurs discrètes énumérées | clients par pays (FR, BE) |
HASH | Répartition équilibrée automatique | événements par utilisateur_id |
L'avantage concret de cette technique
Une requête filtrée sur la colonne de partitionnement n'a besoin d'examiner qu'un seul tiroir, jamais toute la table : c'est le "partition pruning".
Prérequis
Le partitionnement s'appuie sur EXPLAIN (leçon 16) pour vérifier concrètement que le "partition pruning" fonctionne : le plan doit montrer qu'une seule partition est scannée.
Passons maintenant à la réplication
La réplication maintient une ou plusieurs copies synchronisées d'une base sur d'autres serveurs, en rejouant en continu le journal des modifications. Elle sert deux objectifs : la haute disponibilité si le serveur principal tombe, et la répartition de charge en lecture.
Une limite importante à retenir avant de continuer
Contrairement au sharding, vu dans une leçon experte plus loin, le partitionnement ne résout PAS le problème d'un serveur physiquement saturé : toutes les partitions restent hébergées sur la même machine. C'est une première étape avant d'envisager une distribution réellement multi-serveurs.
Piège fréquent
Croire que partitionner une table réglera un problème de serveur saturé en CPU ou en disque est une erreur fréquente : toutes les partitions restent sur la même machine physique. Pour distribuer réellement la charge entre plusieurs serveurs, il faut du sharding, une architecture bien plus complexe.
Commandes & code
Réplication et partitionnement
-- PARTITIONNEMENT : diviser une grosse table en sous-tables physiques
-- Le partitionnement par plage (RANGE) est idéal pour des données temporelles
CREATE TABLE commandes (
id BIGINT,
client_id INTEGER,
montant DECIMAL(10, 2),
cree_le DATE NOT NULL
) PARTITION BY RANGE (cree_le);
CREATE TABLE commandes_2024 PARTITION OF commandes
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
CREATE TABLE commandes_2025 PARTITION OF commandes
FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
-- Une requête filtrée sur cree_le n'accède qu'à la partition concernée (partition pruning)
EXPLAIN SELECT * FROM commandes WHERE cree_le >= '2025-06-01' AND cree_le < '2025-07-01';
-- -> ne scanne QUE commandes_2025, pas commandes_2024
-- Partitionnement par LISTE (valeurs discrètes)
CREATE TABLE clients (
id INTEGER,
pays VARCHAR(2) NOT NULL,
nom VARCHAR(100)
) PARTITION BY LIST (pays);
CREATE TABLE clients_fr PARTITION OF clients FOR VALUES IN ('FR');
CREATE TABLE clients_be PARTITION OF clients FOR VALUES IN ('BE', 'LU');
CREATE TABLE clients_autres PARTITION OF clients DEFAULT;
-- Partitionnement par HASH (répartition équilibrée sans logique métier)
CREATE TABLE evenements (
id BIGINT,
utilisateur_id INTEGER NOT NULL,
payload JSONB
) PARTITION BY HASH (utilisateur_id);
CREATE TABLE evenements_p0 PARTITION OF evenements FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE evenements_p1 PARTITION OF evenements FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE evenements_p2 PARTITION OF evenements FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE evenements_p3 PARTITION OF evenements FOR VALUES WITH (MODULUS 4, REMAINDER 3);
-- REPLICATION : concepts (configuration réelle hors du langage SQL pur)
-- Réplication physique en streaming (PostgreSQL) : le réplica rejoue le WAL du primaire
-- postgresql.conf sur le primaire :
-- wal_level = replica
-- max_wal_senders = 10
-- Sur le réplica :
-- primary_conninfo = 'host=primaire port=5432 user=replicateur'
-- Vérifier le décalage de réplication (lag) depuis le primaire
SELECT client_addr, state, sent_lsn, replay_lsn,
(pg_current_wal_lsn() - replay_lsn) AS octets_de_retard
FROM pg_stat_replication;
-- Répartir la charge : écritures sur le primaire, lectures sur les réplicas
-- (routage applicatif : requêtes SELECT -> pool de connexion "réplica",
-- INSERT/UPDATE/DELETE -> connexion "primaire")
-- Sharding (partitionnement horizontal ENTRE plusieurs serveurs, pas seulement dans un seul)
-- Chaque shard héberge un sous-ensemble de clients (ex: par hash(client_id) % nb_shards)
-- Compromis : les JOIN cross-shard deviennent impossibles ou très coûteux
-- -> à réserver aux tables qui dépassent les capacités d'un seul serveurRésumé
- Le partitionnement (RANGE/LIST/HASH) découpe une grosse table en sous-tables physiques pour accélérer les requêtes filtrées et faciliter la purge (
DROPd'une partition entière). - Le "partition pruning" permet au planificateur d'ignorer les partitions non concernées par une requête.
- La réplication physique en streaming synchronise un ou plusieurs réplicas depuis le WAL du primaire, pour la haute disponibilité et le scaling en lecture.
- Le sharding distribue les données ENTRE plusieurs serveurs, au prix de jointures inter-shards complexes : réservé aux très grands volumes.
Exercices pratiques
Mission : dompter une table de 300 millions de commandes
Objectif : Partitionner une grosse table par plage de dates et vérifier le partition pruning, en distinguant partitionnement et sharding.
Contexte
La table commandes d'une plateforme SaaS dépasse désormais 300 millions de lignes. Les requêtes ne filtrent presque toujours que sur les derniers mois, mais elles restent lentes car le moteur doit toujours envisager l'ensemble de la table. La direction technique demande aussi si cette même opération réglerait le problème du serveur qui approche de la saturation disque.