Guide complet du partitionnement et sharding — partition range, list, hash (PostgreSQL, MySQL, MongoDB), sharding horizontal (MongoDB, MySQL Cluster, Vitess), et stratégies de distribution des données.
Guide complet du partitionnement et sharding — partition range, list, hash (PostgreSQL, MySQL, MongoDB), sharding horizontal (MongoDB, MySQL Cluster, Vitess), et stratégies de distribution des données.
Compétence Sharding et Partitionnement — Distribution des Données à Grande Échelle
Vue d'ensemble
Le partitionnement (partitioning) divise une table logique en segments physiques plus petits. Le sharding distribue ces segments sur plusieurs serveurs (scale-out). Ensemble, ils permettent de dépasser les limites d'une seule machine.
Cette compétence distingue clairement :
Partitionnement vertical : diviser une table par colonnes (rare)
Partitionnement horizontal : diviser par lignes (range, list, hash)
Veut archiver des données anciennes sans supprimer
Doit distribuer une charge sur plusieurs serveurs
A besoin de paralléliser les requêtes sur plusieurs nœuds
Veut configurer le sharding MongoDB, Vitess, ou MySQL Cluster
Demande de migrer d'une instance monolithique vers une architecture distribuée
1. Partitionnement PostgreSQL
1.1 Partition Range (par périodes)
-- Table partitionnée par moisCREATE TABLE mesures (
id BIGSERIAL,
ts TIMESTAMPTZ NOT NULL,
machine_id INTNOT NULL,
temperature NUMERIC,
pression NUMERIC,
PRIMARY KEY (id, ts) -- la clé de partition DOIT faire partie de la PK
) PARTITIONBYRANGE (ts);
-- Création des partitions mensuellesCREATE TABLE mesures_2025_01 PARTITIONOF mesures
FORVALUESFROM ('2025-01-01') TO ('2025-02-01')
TABLESPACE fast_storage;
CREATE TABLE mesures_2025_02 PARTITION mesures
() ()
TABLESPACE fast_storage;
mesures_defaut mesures ;
OF
FOR
VALUES
FROM
'2025-02-01'
TO
'2025-03-01'
-- Partition par défaut (attrape les hors-limites)
CREATE TABLE
PARTITION
OF
DEFAULT
1.2 Partition List (catégories discrètes)
CREATE TABLE logs_evenements (
id BIGSERIAL,
niveau TEXT NOT NULL,
message TEXT,
ts TIMESTAMPTZ
) PARTITIONBY LIST (niveau);
CREATE TABLE logs_info PARTITIONOF logs_evenements
FORVALUESIN ('INFO', 'DEBUG');
CREATE TABLE logs_warn PARTITIONOF logs_evenements
FORVALUESIN ('WARN', 'ERROR');
CREATE TABLE logs_critical PARTITIONOF logs_evenements
FORVALUESIN ('CRITICAL', 'FATAL');
-- Détacher une partition (quasi-instantané, pas de copie)ALTER TABLE mesures DETACH PARTITION mesures_2024_01;
-- Attacher une partition (validation des contraintes)ALTER TABLE mesures ATTACH PARTITION mesures_2025_03
FORVALUESFROM ('2025-03-01') TO ('2025-04-01');
-- Valider sans bloquer (PostgreSQL 16+)ALTER TABLE mesures ATTACH PARTITION mesures_2025_03
FORVALUESFROM ('2025-03-01') TO ('2025-04-01')
WITHOUT VALIDATION;
2. Partitionnement MySQL (InnoDB)
2.1 Range avec sous-partitions
CREATE TABLE transactions (
id BIGINTNOT NULL,
date_transaction DATENOT NULL,
montant DECIMAL(10,2),
client_id INT,
PRIMARY KEY (id, date_transaction)
) PARTITIONBYRANGE (YEAR(date_transaction))
SUBPARTITION BY HASH (MONTH(date_transaction))
SUBPARTITIONS 4 (
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
2.2 Partition Exchange pour archivage
-- Échange instantané entre partition et tableCREATE TABLE transactions_2024_archive LIKE transactions;
ALTER TABLE transactions EXCHANGE PARTITION p2024 WITHTABLE transactions_2024_archive;
-- La table transactions_2024_archive contient maintenant les données-- On peut la déplacer, la compresser, ou la stocker ailleurs
Citus transforme PostgreSQL en base de données distribuée compatible SQL.
-- Activer CitusCREATE EXTENSION citus;
-- Ajouter des nœuds workersSELECT master_add_node('worker1.example.com', 5432);
SELECT master_add_node('worker2.example.com', 5432);
SELECT master_add_node('worker3.example.com', 5432);
-- Créer une table distribuéeCREATE TABLE mesures (
capteur_id INT,
ts TIMESTAMPTZ,
temperature NUMERIC
);
-- Choisir la colonne de distributionSELECT create_distributed_table('mesures', 'capteur_id');
-- Colocate deux tables (évite les requêtes cross-shard)SELECT create_distributed_table('capteurs', 'id');
SELECT create_reference_table('types_capteurs'); -- copiée partout-- Requêtes distributées (SQL transparent)SELECT capteur_id, COUNT(*)
FROM mesures
WHERE ts > NOW() -INTERVAL'1 hour'GROUPBY capteur_id
ORDERBYCOUNT(*) DESC;
6. Stratégies de Clé de Shard
Stratégie
Avantages
Inconvénients
Idéal pour
Hashed
Distribution uniforme garantie
Range scans impossibles, pas de localité
Lookup par ID, sessions
Range
Range scans efficaces, aggregation locale
Hot spots sur les clés récentes
Séries temporelles
Zone-based
Localité des données (régions)
Déséquilibre si une zone domine
Applications multirégions
Lookup table
Distribution selon attribut secondaire
Requête supplémentaire, complexité
Data où la PK n'est pas la bonne clé
Directory-based
Contrôle total de la distribution
SPOF sur le service de routage
Applications legacy
7. Anti-Patterns du Sharding
7.1 Hot Spot (clé mal choisie)
// MAUVAIS : partition par date avec écritures concentrées sur la partition courante
sh.shardCollection("logs.journal", { date: 1 });
// MEILLEUR : hashed sur un champ composite
sh.shardCollection("logs.journal", { serveur_id: 1, date: 1 });
7.2 Cross-shard Queries
-- MAUVAIS (MySQL avec Vitess / Citus)-- JOIN entre deux tables sur des shards différents = très lent-- BON : colocation des tables fréquemment jointesSELECT create_distributed_table('commandes', 'client_id');
SELECT create_distributed_table('lignes_commande', 'client_id'); -- colocated
7.3 Resharding coûteux
Le resharding (changer le nombre de shards) est LOURD. Anticiper :
MongoDB : balancer automatique (mais lent : ~50MB/s par nœud)
Vitess : resharding vertical (split sans downtime)
Citus : rebalance_table_shards() avec mouvement des données
Pièges Courants
Partitionnement sans pruning. Une requête qui scannne toutes les partitions est plus lente que sans partitionnement. Vérifier avec EXPLAIN que seules les partitions pertinentes sont scannées.
Trop de partitions. PostgreSQL gère bien jusqu'à ~1000 partitions, au-delà le planner ralentit. Planifier maximum 12-24 par an pour un partitionnement mensuel.
Index globaux vs locaux. Dans PostgreSQL, les index sont locaux à chaque partition. MySQL les index globaux n'existent pas. MongoDB a un index global sur la collection.
Clé de partition qui change. On ne peut pas changer la clé de partition d'une table existante. Créer une nouvelle table partitionnée et migrer les données avec pg_transport ou INSERT...SELECT.
Distribution non uniforme. Une clé de shard mal choisie crée des shards surchargés. Monitorer la taille des chunks/chunks régulièrement.
Transactions cross-shard. MongoDB et Citus supportent les transactions cross-shard, mais elles sont beaucoup plus lentes. Minimiser les transactions qui traversent les shards.
Checklist
Type de partitionnement adapté : range (temporel), list (catégoriel), hash (uniforme)
Clé de partition/sharding a une cardinalité élevée
Partition pruning confirmé via EXPLAIN
Pas plus de 1000 partitions par table (PostgreSQL)