Zurück zur Startseite

Partitionierung in ClickHouse: Strategien und Operationen

Der Artikel erklärt die Partitionierung in ClickHouse als Mechanismus zur physischen Datentrennung auf Ordnerebene. Er behandelt PARTITION BY-Funktionen (toYYYYMM, toYYYYMMDD), Ansicht über system.parts, Operationen DROP/DETACH/ATTACH/FREEZE/MOVE PARTITION, Strategie zur Partitionsgrößenauswahl (100–1000 pro Server) und automatisches Löschen alter Daten über ein Skript.

Partitionierung in ClickHouse: Vollständiger Leitfaden
Advertisement 728x90

Partitionierung in ClickHouse: So verwalten Sie Daten auf Ordnerebene

1. Warum Partitionierung – Datenisolierung nach Zeiträumen

Stellen Sie sich vor, Sie speichern alle Wetten eines Online-Casinos der letzten drei Jahre. Das sind Milliarden von Zeilen. Der Geschäftsinhaber sagt plötzlich: „Wir brauchen nur Daten der letzten 6 Monate; löschen Sie alles Ältere.“

In einer regulären Datenbank würden Sie DELETE FROM bets WHERE created_at < '2025-01-01' schreiben. In ClickHouse würde eine solche Abfrage … sehr lange dauern. Denn DELETE in ClickHouse ist keine sofortige Löschung, sondern ein asynchrones Umschreiben von Datenteilen ohne die markierten Zeilen.

Aber es gibt einen Weg, die Löschung sofort zu machen – Partitionierung. Wenn Daten in Partitionen aufgeteilt sind (logische Blöcke, die jeweils physisch in einem separaten Ordner auf der Festplatte gespeichert sind), löscht DROP PARTITION einen gesamten Ordner in Millisekunden. Kein Scannen von Zeilen, kein Umschreiben – einfach rm -rf auf Dateisystemebene.

Google AdInline article slot

Analogie aus dem echten Leben: Stellen Sie sich vor, Sie haben Papierarchive über mehrere Jahre. Sie sind in Kartons aufbewahrt, jeder Karton für einen Monat. Wenn Sie Daten für Januar 2024 löschen müssen, nehmen Sie einfach den Karton mit der Aufschrift „Januar 2024“ zum Müllcontainer. Kein Durchgehen jedes Blattes. Partitionen in ClickHouse sind diese Kartons.

Warum Sie Partitionierung noch brauchen:

  • Backups – Sie können nur die benötigte Partition einfrieren (FREEZE).
  • Datenverschiebung – heiße Daten (häufig abgefragt) auf schnellen SSDs, kalte Daten (selten) auf langsamen HDDs oder Cloud-Speicher (S3).
  • SELECT-Beschleunigung – wenn die WHERE-Klausel die Partitionierungsspalte enthält, weiß ClickHouse sofort, welche Ordner gelesen und welche ignoriert werden müssen.

2. PARTITION BY – Syntax und Beispiele

Die Partitionierung wird beim Erstellen einer Tabelle mit PARTITION BY definiert. Das häufigste Muster ist die Aufteilung nach Datum.

Google AdInline article slot
-- Erstellen einer Wetten-Tabelle mit monatlichen Partitionen
CREATE TABLE bets
(
    user_id     UInt64,
    amount      Decimal(18,2),
    created_at  DateTime
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(created_at)   -- Partition = Jahr + Monat, z.B. 202512
ORDER BY (user_id, created_at);

Was hier passiert:

  • toYYYYMM(created_at) – eine ClickHouse-Funktion, die einen Datumszeitwert 2025-12-15 14:30:00 in die Zahl 202512 umwandelt (Jahr 2025, Monat 12). Alle Zeilen mit derselben 202512 gehen in eine Partition.
  • Der Partitionsname ist nur eine Zeichenkette. ClickHouse erstellt einen Ordner auf der Festplatte mit einem Namen wie 202512_1_1_0 (Details sind nicht wichtig, aber intern ist er an 202512 gebunden).

Andere zeitbasierte Partitionierungsoptionen:

-- Nach Tag (Vorsicht! kann zu viele Partitionen erzeugen)
PARTITION BY toYYYYMMDD(created_at)   -- 20251215

-- Nach Stunde (sehr granular, fast nie benötigt)
PARTITION BY toStartOfHour(created_at)   -- 2025-12-15 14:00:00

-- Nach Woche
PARTITION BY toWeek(created_at)   -- Wochennummer im Jahr

-- Nach Jahr
PARTITION BY toYear(created_at)   -- 2025

Was passiert, wenn Sie PARTITION BY gar nicht angeben? ClickHouse erstellt eine einzelne Partition namens all. Alle Daten befinden sich in einem Ordner. Sie können nur mit DELETE (langsam) oder TRUNCATE (alles auf einmal) löschen. Für die meisten Zeitreihentabellen ist das eine schlechte Idee.

Google AdInline article slot

3. Partitionsauswahlstrategie – Der optimale Bereich

Warum sollten Partitionen nicht zu klein sein?

ClickHouse mag nicht zu viele Partitionen (empfohlen maximal 1000–2000). Denn:

  • Jede Partition ist ein separater Ordner mit Metadaten.
  • Beim Einfügen von Daten kann ClickHouse Teile in verschiedenen Partitionen erstellen.
  • Hintergrund-Merges arbeiten innerhalb einer Partition, nicht zwischen ihnen.
  • Die Tabelle system.parts (Metadaten über Teile) wird riesig.

Was passiert, wenn Sie stündlich partitionieren bei einer Last von 1 Million Zeilen pro Stunde? In einem Jahr erhalten Sie 365 * 24 = 8760 Partitionen. Das ist bereits schlecht. Bei jedem Einfügen öffnet ClickHouse Dateideskriptoren für Tausende von Ordnern. SELECT mit Datumsfilterung ist schnell, aber Systemoperationen (Backups, Löschung, Auflisten von Partitionen) werden langsamer.

Warum sollten Partitionen nicht zu groß sein?

Wenn eine Partition ein Jahr ist, löscht DROP PARTITION sofort alles für dieses Jahr. Das ist praktisch, aber:

  • Selbst ein SELECT für einen einzelnen Tag muss die gesamte Jahrespartition scannen.
  • Sie können nicht schnell einen einzelnen Monat löschen – Sie müssten das Jahr löschen oder DELETE (langsam) verwenden.
  • Das Verschieben von „heißen“ und „kalten“ Daten (z.B. letzter Monat auf SSD, Rest auf HDD) ist auf Monatsebene unmöglich.

Faustregel

Last Partitionsgröße Beispiel
Milliarden Zeilen pro Monat Tag (toYYYYMMDD) IoT-Sensordaten, CDN-Logs
Hunderte Millionen pro Monat Monat (toYYYYMM) Casino-Wetten, Transaktionen
Zehn Millionen pro Monat Monat oder Quartal Verkaufsanalysen
Tausende Zeilen pro Monat Jahr Langsam veränderliche Referenzdaten

Hauptkriterium: Nach der Partitionierung sollten Sie zwischen 100 und 1000 Partitionen pro Server haben. Wenn Sie 10.000 Partitionen haben, haben Sie übertrieben.

4. Anzeigen von Partitionen – system.parts

Um zu sehen, welche Partitionen in einer Tabelle existieren und wie viele Daten sie enthalten, verwenden Sie die Systemtabelle system.parts.

-- Alle Partitionen der bets-Tabelle anzeigen
SELECT 
    partition,                          -- Partitionsname (z.B. 202512)
    name,                               -- Spezifischer Teilname
    rows,                               -- Anzahl der Zeilen in diesem Teil
    bytes_on_disk,                      -- Größe auf der Festplatte in Bytes
    modification_time,                  -- Letzte Änderungszeit
    active                              -- Ob der Teil aktiv (1) oder gelöscht (0) ist
FROM system.parts
WHERE table = 'bets' AND active = 1    -- nur aktive Teile
ORDER BY partition DESC;

Aufschlüsselung:

  • partition – was Sie in PARTITION BY angegeben haben. Nützlich zum Gruppieren.
  • name – interner Name des Datenteils, enthält Partitionsnummer und Version.
  • active = 1 – der Teil wird zum Lesen verwendet. Bei 0 ist der Teil zum Löschen markiert, existiert aber noch physisch.
  • bytes_on_disk – zeigt, wie viel Speicherplatz die Partition belegt.

Warum kann es mehrere Teile in einer Partition geben? Weil Sie Daten in Batches einfügen. ClickHouse führt sie nicht sofort zusammen. Innerhalb einer einzelnen Partition (202512) können 5–10 kleine Teile existieren, die schließlich zu einem großen zusammengeführt werden.

Aggregierte Abfrage – Summe nach 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. Partitionsoperationen – DROP, DETACH, ATTACH, FREEZE

Dies ist der Hauptgrund, warum Partitionierung so beliebt ist. Sie können mit Partitionen Dinge tun, die auf Zeilenebene nicht möglich sind.

DROP PARTITION – Sofortige Löschung

-- Alle Daten für Dezember 2025 löschen
ALTER TABLE bets DROP PARTITION '202512';

-- Daten älter als 90 Tage löschen (dynamisch)
-- Zuerst den Partitionsnamen für 90 Tage vor heute berechnen
ALTER TABLE bets DROP PARTITION toYYYYMM(today() - interval 90 day);

Nach diesem Befehl verschwindet der Partitionsordner von der Festplatte. Die Operation dauert Millisekunden, unabhängig davon, wie viele Zeilen darin waren – eine Million oder eine Milliarde.

Warum ist das sicher? Weil Partitionen isoliert sind. Das Löschen einer Partition beeinflusst andere nicht.

DETACH PARTITION – Vorübergehende Deaktivierung

-- Die Partition trennen (Daten bleiben auf der Festplatte, sind aber für SELECT nicht verfügbar)
ALTER TABLE bets DETACH PARTITION '202512';

Die Partition wird in den Unterordner detached verschoben. Sie nimmt nicht an Abfragen teil, aber Sie können sie wiederherstellen.

Wann wird dies benötigt:

  • Sie vermuten Datenkorruption und möchten sie vorübergehend ausblenden.
  • Sie möchten die Partition auf einen anderen Server kopieren (dann auf dem neuen Server ATTACH).

ATTACH PARTITION – Wiederherstellen einer getrennten Partition

-- Die Partition zurückbringen (wenn sie sich im detached-Ordner befindet)
ALTER TABLE bets ATTACH PARTITION '202512';

FREEZE PARTITION – Sofortiges Backup

-- Ein Backup der Dezember-2025-Partition erstellen
ALTER TABLE bets FREEZE PARTITION '202512';

ClickHouse erstellt Hardlinks zu den Partitionsdateien im Ordner shadow/. Dies ist kein Kopieren der Daten (schnell), sondern nur das Erstellen zusätzlicher Zeiger auf dieselben Blöcke auf der Festplatte. Dann können Sie shadow auf einen anderen Server kopieren.

Warum ist das besser als ein reguläres Backup? Weil Sie keine Schreibvorgänge stoppen müssen und es keinen Speicherplatz für Datenverdopplung verschwendet.

MOVE PARTITION – Für abgestuften Speicher

Weitere Details in Abschnitt 6.

6. MOVE PARTITION – Abgestufter Speicher (SSD → HDD → S3)

In ClickHouse können Sie mehrere Speicherstufen mit unterschiedlichen Kosten und Geschwindigkeiten konfigurieren. Zum Beispiel:

  • Heiße Daten (letzter Monat) – auf schnellen NVMe-SSDs
  • Warme Daten (2–6 Monate) – auf regulären HDDs
  • Kalte Daten (älter als 6 Monate) – in der Cloud S3 (günstig, aber langsam)

Partitionen ermöglichen es Ihnen, Daten mit einem einzigen Befehl zwischen diesen Stufen zu verschieben.

Konfiguration in config.xml (vereinfacht):

<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>

Verschieben einer Partition von SSD auf HDD:

-- Daten für Januar 2025 (nicht mehr schnell benötigt) auf HDD verschieben
ALTER TABLE bets MOVE PARTITION '202501' TO VOLUME 'cold';

Was passiert: ClickHouse verschiebt den Partitionsordner physisch von SSD auf HDD. SELECT funktioniert weiterhin, ist aber etwas langsamer (wegen HDD). DROP PARTITION bleibt schnell.

Analogie: Sie verschieben alte Ordner von einem schnellen Schrank neben Ihnen zu einem entfernten Archivschrank. Der Zugriff ist immer noch möglich, aber es dauert länger, dorthin zu gelangen.

7. Partitionierung nach mehreren Spalten

Manchmal müssen Sie Daten nicht nur nach Zeit, sondern auch nach einer anderen Dimension aufteilen. Zum Beispiel haben Sie eine Multi-Brand-Plattform (mehrere Casinos in einer Datenbank). Sie möchten alte Daten für jede Marke separat löschen und möglicherweise auf verschiedenen Festplatten speichern.

-- Wetten-Tabelle für 5 Marken, Partitionen nach Monat UND Marke
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)   -- Zwei Spalten!
ORDER BY (brand_id, user_id, created_at);

Wie es funktioniert:

  • Jede eindeutige Kombination aus (Jahr+Monat, brand_id) wird zu einer separaten Partition.
  • Für Dezember 2025 und Marke 1 – Partition ('202512', 1).
  • Für Dezember 2025 und Marke 2 – Partition ('202512', 2).

Warum das nützlich ist:

  • DROP PARTITION kann Daten für eine bestimmte Marke in einem bestimmten Monat löschen.
  • MOVE PARTITION kann alte Daten für Marke A auf HDD verschieben, während Marke B (Premium) auf SSD bleibt.

So löschen Sie eine Partition für eine bestimmte Marke:

-- Daten für casino_A für Dezember 2025 löschen
ALTER TABLE bets_multi_brand DROP PARTITION ('202512', 1);

Aber es gibt eine Nuance: Der Partitionsname ist jetzt ein Tupel. In system.parts wird er als ('202512', '1') angezeigt. Das ist normal.

8. Wie sich Partitionierung auf die Leistung auswirkt

Auswirkung auf INSERT

Beim Einfügen von Daten betrachtet ClickHouse den PARTITION BY-Ausdruck und leitet die Zeile an die entsprechende Partition weiter. Wenn Sie 1000 Partitionen haben, ist das schnell. Bei 100.000 muss jeder Einfügevorgang den richtigen Ordner bestimmen, was Schreibvorgänge verlangsamt.

Was passiert, wenn ein einzelner INSERT Zeilen aus verschiedenen Partitionen enthält? ClickHouse verteilt sie auf verschiedene Ordner – das ist normal, aber etwas langsamer, als wenn alle Zeilen aus einer Partition stammen.

Tipp: Wenn Sie Daten in Batches einfügen (z.B. einmal pro Minute), versuchen Sie, die Zeilen in einem Batch innerhalb eines kurzen Zeitraums zu halten. Dann fallen sie in eine oder zwei Partitionen, was das Einfügen beschleunigt.

Auswirkung auf SELECT

Die Partitionierung beschleunigt SELECT nur, wenn die WHERE-Klausel eine Bedingung für die Partitionierungsspalte enthält. ClickHouse verwendet Partitionen für grobe Filterung: Es prüft, welche Partitionen benötigt werden, und liest nur deren Ordner.

-- SCHNELL: Partition filtert alle Daten außerhalb Dezember 2025 aus
SELECT count() FROM bets 
WHERE created_at BETWEEN '2025-12-01' AND '2025-12-31';

-- LANGSAM: Partition wird nicht genutzt, alle Partitionen werden gescannt
SELECT count() FROM bets 
WHERE amount > 1000;   -- kein Filter auf created_at

Warum nicht immer sehr fein partitionieren? Weil:

  • Das Lesen aus 1000 kleinen Partitionen (z.B. nach Tag über 3 Jahre) kann langsamer sein als aus 36 großen (nach Monat), wenn die Abfrage einen großen Bereich abdeckt. ClickHouse öffnet einen Dateideskriptor pro Partition.
  • Indizes (Primärschlüssel) sind oft effektiver als feine Partitionierung.

Faustregel: Optimieren Sie zuerst ORDER BY (Index), dann die Partitionierung. Partitionen dienen der Datenverwaltung (DROP, MOVE), nicht nur der Beschleunigung von SELECT.

9. Häufiger Fehler: Zu granulare Partitionierung

Dies ist der häufigste Schmerzpunkt für ClickHouse-Anfänger.

Beispiel für einen falschen Ansatz:

-- SCHLECHT: tägliche Partitionen für eine Tabelle mit 10 Millionen Zeilen pro Tag
CREATE TABLE logs_bad
(
    created_at DateTime,
    message String
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(created_at)   -- Vorsicht!
ORDER BY created_at;

Über 3 Jahre erhalten Sie 365 * 3 = 1095 Partitionen. Das ist noch tolerierbar (aber grenzwertig). Über 10 Jahre – 3650 Partitionen, was schlecht ist. Das System beginnt langsamer zu werden.

Noch schlimmer – stündlich für Daten mit einer Last von 1 Million Datensätzen pro Stunde: In einem Jahr 8760 Partitionen. Bei jedem Einfügen sucht oder erstellt ClickHouse einen Ordner für die aktuelle Stunde. SELECT * FROM system.parts dauert Sekunden. Hintergrund-Merges werden überlastet.

Anzeichen für zu viele Partitionen:

  1. Die Abfrage SELECT * FROM system.parts WHERE table = 'mytable' dauert länger als 1 Sekunde.
  2. ClickHouse-Logs zeigen Warnungen: Too many parts (300+).
  3. ALTER TABLE ... DROP PARTITION funktioniert nicht sofort, sondern dauert mehrere Sekunden.

Was tun, wenn Sie bereits zu fein partitioniert haben? Sie können Partitionen mit ALTER TABLE ... MODIFY PARTITION BY ... zusammenführen, aber das ist komplex. Einfacher ist es, eine neue Tabelle mit korrekter Partitionierung zu erstellen, Daten zu migrieren und umzubenennen.

10. Skript zur automatischen Löschung alter Partitionen

In der Praxis müssen Sie Daten nur für, sagen wir, die letzten 90 Tage behalten. Sich jeden Monat daran zu erinnern, alte Partitionen zu löschen, ist keine Option. Sie brauchen Automatisierung.

Option 1: Periodische Abfrage per cron oder Task

-- Alle Partitionen löschen, die älter als 90 Tage sind
-- Einmal täglich um 3:00 Uhr ausführen
ALTER TABLE bets DROP PARTITION WHERE partition < toYYYYMM(today() - interval 90 day);

Wie es funktioniert:

  • toYYYYMM(today() - interval 90 day) – berechnet den Partitionsnamen für das Datum vor 90 Tagen. Wenn heute der 2026-06-11 ist, dann ist vor 90 Tagen der 2026-03-13, toYYYYMM ergibt 202603.
  • partition < 202603 – löscht alle Partitionen mit Namen 202602, 202601, 202512 usw.

Wichtig: Diese Abfrage funktioniert nur, wenn Partitionsnamen Zahlen sind (Jahr+Monat). Bei Zeichenkettennamen (z.B. '2025-12') benötigen Sie einen anderen Vergleich.

Option 2: Sichereres Skript mit gespeicherten Listen

-- Liste der Partitionen finden, die älter als N Tage sind
SELECT partition
FROM system.parts
WHERE table = 'bets' 
  AND active = 1
  AND toDate(parseDateTimeBestEffort(partition)) < today() - interval 90 day
GROUP BY partition;

-- Für jede gefundene Partition DROP ausführen (aus einem externen Skript, nicht direkt in SQL)

Warum nicht DROP PARTITION WHERE partition < ... mit dynamischer Berechnung? Denn wenn die Tabelle Partitionen mit nicht standardmäßigen Namen hat (z.B. 'all' oder manuell erstellte), könnte die Bedingung unerwartet reagieren. Besser zuerst die Liste anzeigen.

Vollständiges Beispielskript für Bash / Python:

#!/bin/bash
# Partitionen löschen, die älter als 90 Tage sind, für Tabelle bets

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

# Grenzdatum berechnen
BORDER_DATE=$(date -d "today - $DAYS_TO_KEEP days" +%Y%m)

# Liste der Partitionen älter als das Grenzdatum abrufen
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
")

# Jede Partition löschen
for PARTITION in $PARTITIONS; do
    echo "Lösche Partition $PARTITION aus $TABLE"
    $CLICKHOUSE_CLIENT --query="ALTER TABLE $TABLE DROP PARTITION '$PARTITION'"
done

Automatisierung per cron:

# Täglich um 3:00 Uhr ausführen
0 3 * * * /usr/local/bin/cleanup_clickhouse_partitions.sh >> /var/log/cleanup.log 2>&1

Was kommt als Nächstes

Jetzt verstehen Sie, wie die Partitionierung die Datenlöschung von einer schmerzhaften Operation in eine sofortige Aktion verwandelt. Nächste Themen:

  • Fortgeschrittene TTL-Strategien (Time-to-Live) – automatisches Löschen oder Verschieben von Zeilen ohne Ihr Eingreifen.
  • Konfiguration von Speicherrichtlinien – wie Sie das Verschieben von Partitionen von SSD nach S3 zeitgesteuert automatisieren.
  • Optimierung von SELECT mit Partitionen – wie Sie Abfragen schreiben, damit ClickHouse 99 % der Partitionen ausfiltert.

Fazit: Die Partitionierung in ClickHouse ist ein Werkzeug zur Verwaltung des Datenlebenszyklus, nicht nur zur Beschleunigung von Abfragen. Wählen Sie die Partitionsgröße so, dass Sie zwischen 100 und 1000 Partitionen pro Server haben. Nicht zu granular, nicht zu grob. Und überprüfen Sie immer system.parts – es wird Ihnen die Wahrheit sagen.


Vorherige:
Nächste: ORDER BY und PRIMARY KEY in ClickHouse: So setzen Sie den Index richtig

— Editorial Team

Advertisement 728x90

Weiterlesen