Retour à l'accueil

Partitionnement dans ClickHouse : Stratégies et Opérations

L'article explique le partitionnement dans ClickHouse comme un mécanisme de séparation physique des données au niveau des dossiers. Il couvre les fonctions PARTITION BY (toYYYYMM, toYYYYMMDD), la visualisation via system.parts, les opérations DROP/DETACH/ATTACH/FREEZE/MOVE PARTITION, la stratégie de choix de taille de partition (100–1000 par serveur), et la suppression automatique des anciennes données via un script.

Partitionnement dans ClickHouse : Guide Complet
Advertisement 728x90

Partitionnement dans ClickHouse : Comment gérer les données au niveau des dossiers

1. Pourquoi partitionner — Isolation des données par périodes

Imaginez que vous stockez tous les paris d'un casino en ligne des trois dernières années. Cela représente des milliards de lignes. Le propriétaire de l'entreprise vous dit soudainement : « Nous n'avons besoin que des données des 6 derniers mois ; supprimez tout ce qui est plus ancien. »

Dans une base de données classique, vous écririez DELETE FROM bets WHERE created_at < '2025-01-01'. Dans ClickHouse, une telle requête prendrait... beaucoup de temps. Car DELETE dans ClickHouse n'est pas une suppression instantanée mais une réécriture asynchrone des parties de données sans les lignes marquées.

Mais il existe un moyen de rendre la suppression instantanée — le partitionnement. Si les données sont divisées en partitions (morceaux logiques, chacun stocké physiquement dans un dossier séparé sur le disque), alors DROP PARTITION supprime un dossier entier en quelques millisecondes. Pas besoin de parcourir les lignes, pas de réécriture — juste un rm -rf au niveau du système de fichiers.

Google AdInline article slot

Analogie concrète : Imaginez que vous ayez des archives papier couvrant plusieurs années. Elles sont rangées dans des boîtes, chaque boîte pour un mois. Si vous devez supprimer les données de janvier 2024, vous prenez simplement la boîte étiquetée « Janvier 2024 » et vous la jetez à la poubelle. Pas besoin de parcourir chaque feuille. Les partitions dans ClickHouse sont ces boîtes.

Pourquoi d'autre avez-vous besoin du partitionnement :

  • Sauvegardes — vous pouvez geler (FREEZE) uniquement la partition souhaitée.
  • Déplacement de données — données chaudes (fréquemment interrogées) sur des SSD rapides, données froides (rares) sur des HDD lents ou du stockage cloud (S3).
  • Accélération des SELECT — si la clause WHERE inclut la colonne de partitionnement, ClickHouse sait immédiatement quels dossiers lire et lesquels ignorer.

2. PARTITION BY — Syntaxe et exemples

Le partitionnement est défini lors de la création d'une table avec PARTITION BY. Le modèle le plus courant est le fractionnement par date.

Google AdInline article slot
-- Créer une table de paris avec des partitions mensuelles
CREATE TABLE bets
(
    user_id     UInt64,
    amount      Decimal(18,2),
    created_at  DateTime
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(created_at)   -- Partition = année + mois, ex. 202512
ORDER BY (user_id, created_at);

Ce qui se passe ici :

  • toYYYYMM(created_at) — une fonction ClickHouse qui convertit une date-heure 2025-12-15 14:30:00 en nombre 202512 (année 2025, mois 12). Toutes les lignes avec le même 202512 vont dans une seule partition.
  • Le nom de la partition est simplement une chaîne. ClickHouse créera un dossier sur le disque avec un nom comme 202512_1_1_0 (les détails ne sont pas importants, mais en interne, il est lié à 202512).

Autres options de partitionnement basées sur le temps :

-- Par jour (attention ! peut créer trop de partitions)
PARTITION BY toYYYYMMDD(created_at)   -- 20251215

-- Par heure (très granulaire, presque jamais nécessaire)
PARTITION BY toStartOfHour(created_at)   -- 2025-12-15 14:00:00

-- Par semaine
PARTITION BY toWeek(created_at)   -- Numéro de semaine dans l'année

-- Par année
PARTITION BY toYear(created_at)   -- 2025

Que se passe-t-il si vous ne spécifiez pas du tout PARTITION BY ? ClickHouse crée une seule partition nommée all. Toutes les données résident dans un seul dossier. Vous ne pouvez supprimer que via DELETE (lent) ou TRUNCATE (tout d'un coup). Pour la plupart des tables de séries temporelles, c'est une mauvaise idée.

Google AdInline article slot

3. Stratégie de sélection des partitions — Le juste milieu

Pourquoi les partitions ne doivent-elles pas être trop petites ?

ClickHouse n'aime pas trop de partitions (recommandé pas plus de 1000–2000). Parce que :

  • Chaque partition est un dossier séparé avec des métadonnées.
  • Lors de l'insertion de données, ClickHouse peut créer des parties dans différentes partitions.
  • Les fusions en arrière-plan s'effectuent au sein d'une partition, pas entre elles.
  • La table system.parts (métadonnées sur les parties) sera énorme.

Que se passe-t-il si vous partitionnez par heure avec une charge d'un million de lignes par heure ? En un an, vous obtenez 365 * 24 = 8760 partitions. C'est déjà mauvais. À chaque insertion, ClickHouse ouvrira des descripteurs de fichiers pour des milliers de dossiers. Les SELECT avec filtrage par date seront rapides, mais les opérations système (sauvegardes, suppression, listage des partitions) ralentiront.

Pourquoi les partitions ne doivent-elles pas être trop grandes ?

Si une partition est d'un an, alors DROP PARTITION supprime tout pour cette année instantanément. C'est pratique, mais :

  • Même un SELECT pour un seul jour devra parcourir toute la partition annuelle.
  • Vous ne pouvez pas supprimer rapidement un seul mois — vous devriez supprimer l'année ou utiliser DELETE (lent).
  • Déplacer les données « chaudes » et « froides » (par exemple, le dernier mois sur SSD, le reste sur HDD) est impossible au niveau mensuel.

Règle empirique

Charge Taille de partition Exemple
Milliards de lignes par mois Jour (toYYYYMMDD) Données de capteurs IoT, logs CDN
Centaines de millions par mois Mois (toYYYYMM) Paris de casino, transactions
Dizaines de millions par mois Mois ou trimestre Analyses de ventes
Milliers de lignes par mois Année Données de référence à évolution lente

Critère principal : Après partitionnement, vous devriez avoir entre 100 et 1000 partitions par serveur. Si vous avez 10 000 partitions, vous avez exagéré.

4. Visualisation des partitions — system.parts

Pour voir quelles partitions existent dans une table et combien de données elles contiennent, utilisez la table système system.parts.

-- Voir toutes les partitions de la table bets
SELECT 
    partition,                          -- Nom de la partition (ex. 202512)
    name,                               -- Nom spécifique de la partie
    rows,                               -- Nombre de lignes dans cette partie
    bytes_on_disk,                      -- Taille sur le disque en octets
    modification_time,                  -- Dernière modification
    active                              -- Si la partie est active (1) ou supprimée (0)
FROM system.parts
WHERE table = 'bets' AND active = 1    -- seulement les parties actives
ORDER BY partition DESC;

Explication :

  • partition — ce que vous avez spécifié dans PARTITION BY. Utile pour le regroupement.
  • name — nom interne de la partie de données, contient le numéro de partition et la version.
  • active = 1 — la partie est utilisée pour la lecture. Si 0, la partie est marquée pour suppression mais existe encore physiquement.
  • bytes_on_disk — indique l'espace consommé par la partition.

Pourquoi peut-il y avoir plusieurs parties dans une même partition ? Parce que vous insérez des données par lots. ClickHouse ne les fusionne pas instantanément. Au sein d'une même partition (202512), il peut y avoir 5 à 10 petites parties qui finiront par fusionner en une seule grande.

Requête agrégée — somme par partition :

SELECT 
    partition,
    sum(rows) AS total_rows,
    sum(bytes_on_disk) AS total_bytes,
    formatReadableSize(sum(bytes_on_disk)) AS human_size
FROM system.parts
WHERE table = 'bets' AND active = 1
GROUP BY partition
ORDER BY partition DESC;

5. Opérations sur les partitions — DROP, DETACH, ATTACH, FREEZE

C'est la principale raison pour laquelle le partitionnement est si populaire. Vous pouvez faire avec les partitions des choses qui ne sont pas possibles au niveau des lignes.

DROP PARTITION — Suppression instantanée

-- Supprimer toutes les données de décembre 2025
ALTER TABLE bets DROP PARTITION '202512';

-- Supprimer les données de plus de 90 jours (dynamiquement)
-- D'abord calculer le nom de la partition pour il y a 90 jours
ALTER TABLE bets DROP PARTITION toYYYYMM(today() - interval 90 day);

Après cette commande, le dossier de la partition disparaît du disque. L'opération prend des millisecondes, quel que soit le nombre de lignes à l'intérieur — un million ou un milliard.

Pourquoi est-ce sûr ? Parce que les partitions sont isolées. En supprimer une n'affecte pas les autres.

DETACH PARTITION — Désactivation temporaire

-- Détacher la partition (les données restent sur le disque mais sont indisponibles pour SELECT)
ALTER TABLE bets DETACH PARTITION '202512';

La partition se déplace dans le sous-dossier detached. Elle ne participe pas aux requêtes, mais vous pouvez la ramener.

Quand est-ce nécessaire :

  • Vous soupçonnez une corruption des données et voulez la cacher temporairement.
  • Vous voulez copier la partition vers un autre serveur (puis l'ATTACHER sur le nouveau serveur).

ATTACH PARTITION — Restauration d'une partition détachée

-- Ramener la partition (si elle est dans le dossier detached)
ALTER TABLE bets ATTACH PARTITION '202512';

FREEZE PARTITION — Sauvegarde instantanée

-- Créer une sauvegarde de la partition de décembre 2025
ALTER TABLE bets FREEZE PARTITION '202512';

ClickHouse crée des liens physiques vers les fichiers de la partition dans le dossier shadow/. Ce n'est pas une copie des données (rapide), juste la création de pointeurs supplémentaires vers les mêmes blocs sur le disque. Ensuite, vous pouvez copier shadow vers un autre serveur.

Pourquoi est-ce mieux qu'une sauvegarde classique ? Parce que vous n'avez pas besoin d'arrêter les écritures et cela ne gaspille pas d'espace en duplication de données.

MOVE PARTITION — Pour le stockage hiérarchisé

Plus de détails dans la section 6.

6. MOVE PARTITION — Stockage hiérarchisé (SSD → HDD → S3)

Dans ClickHouse, vous pouvez configurer plusieurs niveaux de stockage avec des coûts et des vitesses différents. Par exemple :

  • Données chaudes (dernier mois) — sur des SSD NVMe rapides
  • Données tièdes (2–6 mois) — sur des HDD classiques
  • Données froides (plus de 6 mois) — dans le cloud S3 (peu coûteux mais lent)

Les partitions vous permettent de déplacer les données entre ces niveaux avec une seule commande.

Configuration dans config.xml (simplifiée) :

<storage_configuration>
    <disks>
        <ssd>
            <path>/mnt/ssd/clickhouse/</path>
        </ssd>
        <hdd>
            <path>/mnt/hdd/clickhouse/</path>
        </hdd>
    </disks>
    <policies>
        <hot_to_cold>
            <volumes>
                <hot>
                    <disk>ssd</disk>
                </hot>
                <cold>
                    <disk>hdd</disk>
                </cold>
            </volumes>
        </hot_to_cold>
    </policies>
</storage_configuration>

Déplacer une partition du SSD vers le HDD :

-- Les données de janvier 2025 (plus besoin de rapidité) passer sur HDD
ALTER TABLE bets MOVE PARTITION '202501' TO VOLUME 'cold';

Ce qui se passe : ClickHouse déplace physiquement le dossier de la partition du SSD vers le HDD. SELECT continue de fonctionner mais sera légèrement plus lent (à cause du HDD). DROP PARTITION reste rapide.

Analogie : Vous déplacez les vieux dossiers d'un classeur rapide près de vous vers un classeur d'archives éloigné. L'accès est toujours possible, mais il faut plus de temps pour y arriver.

7. Partitionnement par plusieurs colonnes

Parfois, vous devez fractionner les données non seulement par temps mais aussi par une autre dimension. Par exemple, vous avez une plateforme multi-marques (plusieurs casinos dans une même base de données). Vous voulez supprimer les anciennes données séparément pour chaque marque et éventuellement les stocker sur des disques différents.

-- Table de paris pour 5 marques, partitions par mois ET par marque
CREATE TABLE bets_multi_brand
(
    brand_id    UInt8,          -- 1 = casino_A, 2 = casino_B, ...
    user_id     UInt64,
    amount      Decimal(18,2),
    created_at  DateTime
)
ENGINE = MergeTree()
PARTITION BY (toYYYYMM(created_at), brand_id)   -- Deux colonnes !
ORDER BY (brand_id, user_id, created_at);

Comment ça marche :

  • Chaque combinaison unique de (année+mois, brand_id) devient une partition séparée.
  • Pour décembre 2025 et la marque 1 — partition ('202512', 1).
  • Pour décembre 2025 et la marque 2 — partition ('202512', 2).

Pourquoi c'est utile :

  • DROP PARTITION peut supprimer les données d'une marque spécifique dans un mois spécifique.
  • MOVE PARTITION peut déplacer les anciennes données de la marque A vers le HDD, tout en gardant la marque B (premium) sur SSD.

Comment supprimer une partition pour une marque spécifique :

-- Supprimer les données de casino_A pour décembre 2025
ALTER TABLE bets_multi_brand DROP PARTITION ('202512', 1);

Mais il y a une nuance : Le nom de la partition est maintenant un tuple. Lorsqu'il est visualisé dans system.parts, il apparaîtra comme ('202512', '1'). C'est normal.

8. Comment le partitionnement affecte les performances

Impact sur INSERT

Lors de l'insertion de données, ClickHouse examine l'expression PARTITION BY et achemine la ligne vers la partition appropriée. Si vous avez 1000 partitions, c'est rapide. Si vous en avez 100 000, chaque insertion doit déterminer le dossier correct, ce qui ralentit les écritures.

Que se passe-t-il si un seul INSERT contient des lignes de différentes partitions ? ClickHouse les distribue dans différents dossiers — c'est normal, mais légèrement plus lent que si toutes les lignes provenaient d'une seule partition.

Conseil : Si vous insérez des données par lots (par exemple, une fois par minute), essayez de garder les lignes d'un lot dans un intervalle de temps court. Ainsi, elles tomberont dans une ou deux partitions, rendant l'insertion plus rapide.

Impact sur SELECT

Le partitionnement accélère SELECT uniquement si la clause WHERE inclut une condition sur la colonne de partitionnement. ClickHouse utilise les partitions pour un élagage grossier : il vérifie quelles partitions sont nécessaires et ne lit que leurs dossiers.

-- RAPIDE : la partition élimine toutes les données en dehors de décembre 2025
SELECT count() FROM bets 
WHERE created_at BETWEEN '2025-12-01' AND '2025-12-31';

-- LENT : la partition n'est pas utilisée, scan de toutes les partitions
SELECT count() FROM bets 
WHERE amount > 1000;   -- pas de filtre sur created_at

Pourquoi ne pas toujours partitionner très finement ? Parce que :

  • Lire à partir de 1000 petites partitions (par exemple, par jour sur 3 ans) peut être plus lent qu'à partir de 36 grandes (par mois) si la requête couvre une large plage. ClickHouse ouvre un descripteur de fichier par partition.
  • Les index (clé primaire) sont souvent plus efficaces qu'un partitionnement fin.

Règle empirique : Optimisez d'abord ORDER BY (index), puis le partitionnement. Les partitions sont pour la gestion des données (DROP, MOVE), pas seulement pour accélérer les SELECT.

9. Erreur courante : Partitionnement trop granulaire

C'est le point de douleur le plus fréquent pour les débutants avec ClickHouse.

Exemple d'une mauvaise approche :

-- MAUVAIS : partitions quotidiennes pour une table avec 10 millions de lignes par jour
CREATE TABLE logs_bad
(
    created_at DateTime,
    message String
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(created_at)   -- Attention !
ORDER BY created_at;

Sur 3 ans, vous obtenez 365 * 3 = 1095 partitions. C'est encore tolérable (mais limite). Sur 10 ans — 3650 partitions, ce qui est mauvais. Le système commencera à ralentir.

Encore pire — par heure pour des données avec une charge d'un million d'enregistrements par heure : En un an, 8760 partitions. À chaque insertion, ClickHouse cherchera ou créera un dossier pour l'heure courante. SELECT * FROM system.parts prendra des secondes. Les fusions en arrière-plan s'étoufferont.

Signes que vous avez trop de partitions :

  1. La requête SELECT * FROM system.parts WHERE table = 'mytable' prend plus d'une seconde.
  2. Les logs de ClickHouse montrent des avertissements : Too many parts (300+).
  3. ALTER TABLE ... DROP PARTITION ne fonctionne pas instantanément mais prend plusieurs secondes.

Que faire si vous avez déjà partitionné trop finement ? Vous pouvez fusionner des partitions via ALTER TABLE ... MODIFY PARTITION BY ..., mais c'est complexe. Plus simple : créer une nouvelle table avec un partitionnement approprié, migrer les données, et renommer.

10. Script pour la suppression automatique des anciennes partitions

En pratique, vous devez conserver les données seulement, disons, les 90 derniers jours. Se rappeler chaque mois de supprimer les anciennes partitions n'est pas une option. Vous avez besoin d'automatisation.

Option 1 : Requête périodique via cron ou Task

-- Supprimer toutes les partitions de plus de 90 jours
-- Exécuter une fois par jour à 3h00
ALTER TABLE bets DROP PARTITION WHERE partition < toYYYYMM(today() - interval 90 day);

Comment ça marche :

  • toYYYYMM(today() - interval 90 day) — calcule le nom de la partition pour la date d'il y a 90 jours. Par exemple, si aujourd'hui est le 2026-06-11, alors il y a 90 jours c'est le 2026-03-13, toYYYYMM donne 202603.
  • partition < 202603 — supprime toutes les partitions avec les noms 202602, 202601, 202512, etc.

Important : Cette requête fonctionne uniquement si les noms de partitions sont des nombres (année+mois). Pour les noms sous forme de chaîne (par exemple, '2025-12'), vous avez besoin d'une comparaison différente.

Option 2 : Script plus sûr utilisant des listes stockées

-- Trouver la liste des partitions de plus de N jours
SELECT partition
FROM system.parts
WHERE table = 'bets' 
  AND active = 1
  AND toDate(parseDateTimeBestEffort(partition)) < today() - interval 90 day
GROUP BY partition;

-- Pour chaque partition trouvée, exécuter DROP (à partir d'un script externe, pas directement en SQL)

Pourquoi ne pas faire DROP PARTITION WHERE partition < ... avec un calcul dynamique ? Parce que si la table a des partitions avec des noms non standard (par exemple, 'all' ou créées manuellement), la condition pourrait se comporter de manière inattendue. Mieux vaut d'abord visualiser la liste.

Exemple complet de script en Bash / Python :

#!/bin/bash
# Supprimer les partitions de plus de 90 jours pour la table bets

CLICKHOUSE_CLIENT="clickhouse-client --host localhost"
TABLE="bets"
DAYS_TO_KEEP=90

# Calculer la date limite
BORDER_DATE=$(date -d "today - $DAYS_TO_KEEP days" +%Y%m)

# Obtenir la liste des partitions plus anciennes que la limite
PARTITIONS=$($CLICKHOUSE_CLIENT --query="
    SELECT DISTINCT partition 
    FROM system.parts 
    WHERE table = '$TABLE' 
      AND active = 1 
      AND partition < '$BORDER_DATE'
      AND partition != 'all'
    FORMAT TabSeparated
")

# Supprimer chaque partition
for PARTITION in $PARTITIONS; do
    echo "Suppression de la partition $PARTITION de $TABLE"
    $CLICKHOUSE_CLIENT --query="ALTER TABLE $TABLE DROP PARTITION '$PARTITION'"
done

Automatisation via cron :

# Exécuter tous les jours à 3h00
0 3 * * * /usr/local/bin/cleanup_clickhouse_partitions.sh >> /var/log/cleanup.log 2>&1

Prochaines étapes

Maintenant vous comprenez comment le partitionnement transforme la suppression de données d'une opération douloureuse en une action instantanée. Prochains sujets :

  • Stratégies avancées de TTL (time-to-live) — suppression ou déplacement automatique des lignes sans votre intervention.
  • Configuration des politiques de stockage — comment automatiser le déplacement des partitions du SSD vers S3 selon un calendrier.
  • Optimisation des SELECT avec les partitions — comment écrire des requêtes pour que ClickHouse élimine 99 % des partitions.

En résumé : Le partitionnement dans ClickHouse est un outil pour gérer le cycle de vie des données, pas seulement pour accélérer les requêtes. Choisissez la taille des partitions de manière à avoir entre 100 et 1000 partitions par serveur. Ne faites pas trop de granularité, ne faites pas trop d'agrégation. Et vérifiez toujours system.parts — il vous dira la vérité.


Précédente:
Suivante: ORDER BY et PRIMARY KEY dans ClickHouse : comment bien choisir son index

— Editorial Team

Advertisement 728x90

Lire ensuite