Zpět na domů

Partitionování v ClickHouse: strategie a operace

Článek vysvětluje partitionování v ClickHouse jako mechanismus fyzického rozdělení dat na úrovni složek. Zkoumá funkce PARTITION BY (toYYYYMM, toYYYYMMDD), prohlížení přes system.parts, operace DROP/DETACH/ATTACH/FREEZE/MOVE PARTITION, strategii výběru velikosti partition (100–1000 na server) a automatické mazání starých dat pomocí skriptu.

Partitionování v ClickHouse: kompletní průvodce
Advertisement 728x90

Partitionování v ClickHouse: Jak spravovat data na úrovni složek

1. Proč je partitionování potřeba — izolace dat podle období

Představ si, že uchováváš všechny sázky z online casina za poslední tři roky. Jsou to miliardy řádků. Majitel firmy najednou řekne: „Potřebujeme data jen za posledních 6 měsíců, všechno starší smaž.“

V běžné databázi bys napsal DELETE FROM bets WHERE created_at < '2025-01-01'. V ClickHouse by takový dotaz trval… velmi dlouho. Protože DELETE v ClickHouse není okamžité smazání, ale asynchronní přepisování částí dat (parts) bez označených řádků.

Ale existuje způsob, jak udělat smazání okamžité — partitionování. Pokud jsou data rozdělena do particí (partition — logické kusy, z nichž každý fyzicky leží v samostatné složce na disku), pak DROP PARTITION smaže celou složku za milisekundy. Není potřeba skenovat řádky, není potřeba přepisovat — prostě rm -rf na úrovni souborového systému.

Google AdInline article slot

Analogický příklad z reálného života: Představ si, že máš papírové archivy za několik let. Jsou uloženy v krabicích, každá krabice je za jeden měsíc. Pokud potřebuješ smazat data za leden 2024, prostě vyneseš krabici s nápisem „leden 2024“ do popelnice. Nemusíš procházet každý list. Partitiony v ClickHouse jsou právě ty krabice.

K čemu ještě partitionování slouží:

  • Zálohy — lze zmrazit (FREEZE) pouze potřebnou partici.
  • Přesun dat — horká data (často dotazovaná) na rychlé SSD, studená (vzácná) na pomalé HDD nebo do cloudového úložiště (S3).
  • Zrychlení SELECT — pokud je v WHERE uveden sloupec partitionování, ClickHouse okamžitě ví, které složky číst a které ignorovat.

2. PARTITION BY — syntaxe a příklady

Partitionování se nastavuje při vytváření tabulky pomocí PARTITION BY. Nejčastější vzor je rozdělení podle data.

Google AdInline article slot
-- Vytvoříme tabulku sázek s particemi podle měsíců
CREATE TABLE bets
(
    user_id     UInt64,
    amount      Decimal(18,2),
    created_at  DateTime
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(created_at)   -- Partition = rok + měsíc, např. 202512
ORDER BY (user_id, created_at);

Co se zde děje:

  • toYYYYMM(created_at) — funkce ClickHouse, která z data-času 2025-12-15 14:30:00 získá číslo 202512 (rok 2025, měsíc 12). Všechny řádky se stejným 202512 spadnou do jedné partitiony.
  • Název partitiony je prostě řetězec. ClickHouse sám vytvoří složku na disku s názvem např. 202512_1_1_0 (detaily nejsou důležité, ale uvnitř bude vazba na 202512).

Další možnosti partitionování podle času:

-- Podle dnů (pozor! může být příliš mnoho particí)
PARTITION BY toYYYYMMDD(created_at)   -- 20251215

-- Podle hodin (velmi jemné, téměř nikdy není potřeba)
PARTITION BY toStartOfHour(created_at)   -- 2025-12-15 14:00:00

-- Podle týdnů
PARTITION BY toWeek(created_at)   -- Číslo týdne v roce

-- Podle roků
PARTITION BY toYear(created_at)   -- 2025

Co se stane, když PARTITION BY neuvedeš vůbec? ClickHouse vytvoří jednu partici s názvem all. Všechna data budou ležet v jedné složce. Smazat lze jen pomocí DELETE (pomalu) nebo TRUNCATE (vše najednou). Pro většinu tabulek s časovými řadami je to špatný nápad.

Google AdInline article slot

3. Strategie výběru partitiony — zlatá střední cesta

Proč by partitiony neměly být příliš jemné?

ClickHouse nemá rád, když je particí příliš mnoho (doporučuje se maximálně 1000–2000). Protože:

  • Každá partition je samostatná složka s metadaty.
  • Při vkládání dat může ClickHouse vytvářet kusy v různých particích.
  • Slučování na pozadí (merge) pracuje uvnitř partitiony, ale ne mezi nimi.
  • Systémová tabulka system.parts (s metadaty o kusech) bude obrovská.

Co se stane, když budeš dělat partitiony po hodinách při zátěži 1 milion řádků za hodinu? Za rok vznikne 365 * 24 = 8760 particí. To už je špatně. Při každém vkládání bude ClickHouse otevírat deskriptory na tisíce složek. SELECT s filtrem podle data bude rychlý, ale systémové operace (zálohy, mazání, prohlížení seznamu particí) začnou zpomalovat.

Proč by partitiony neměly být příliš velké?

Pokud je partitiona rok, pak DROP PARTITION smaže vše za rok najednou. To je pohodlné, ale:

  • Při SELECT i za jediný den bude nutné prohledávat celou roční partici.
  • Nelze rychle smazat jeden měsíc — musíš smazat rok nebo provést DELETE (pomalu).
  • Přesun „horkých“ a „studených“ dat (např. poslední měsíc na SSD, zbytek na HDD) není možný na úrovni jednoho měsíce.

Pravidlo palce

Zátěž Velikost partitiony Příklad
Miliardy řádků za měsíc Den (toYYYYMMDD) Data z IoT senzorů, logy CDN
Stovky milionů za měsíc Měsíc (toYYYYMM) Sázky v casinu, transakce
Desítky milionů za měsíc Měsíc nebo čtvrtletí Analytika prodejů
Tisíce řádků za měsíc Rok Pomalu se měnící číselníky

Hlavní kritérium: Po partitionování by mělo vzniknout 100 až 1000 particí na server. Pokud máš 10 000 particí — přehnal jsi to.

4. Prohlížení particí — system.parts

K zobrazení, jaké partitiony jsou v tabulce a kolik v nich je dat, slouží systémová tabulka system.parts.

-- Podíváme se na všechny partitiony tabulky bets
SELECT 
    partition,                          -- Název partitiony (např. 202512)
    name,                               -- Název konkrétního kusu (part)
    rows,                               -- Počet řádků v tomto kusu
    bytes_on_disk,                      -- Velikost na disku v bajtech
    modification_time,                  -- Čas poslední změny
    active                              -- Je kus aktivní (1) nebo již smazaný (0)
FROM system.parts
WHERE table = 'bets' AND active = 1    -- pouze aktivní kusy
ORDER BY partition DESC;

Co je co:

  • partition — to, co jsi uvedl v PARTITION BY. Užitečné pro seskupování.
  • name — interní název kusu dat, obsahuje číslo partitiony a verzi.
  • active = 1 — kus se používá pro čtení. Pokud 0 — kus je označen k smazání, ale fyzicky stále existuje.
  • bytes_on_disk — ukazuje, kolik místa partitiona zabírá.

Proč může být v jedné partitioně několik kusů? Protože vkládáš data po dávkách. ClickHouse je neslučuje okamžitě. Uvnitř jedné partitiony (202512) může být 5–10 malých kusů, které se časem slijí do jednoho velkého.

Agregovaný dotaz — součet podle particí:

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. Operace s particemi — DROP, DETACH, ATTACH, FREEZE

To je hlavní důvod, proč je partitionování tak oblíbené. S particemi lze dělat věci, které nejsou na úrovni řádků možné.

DROP PARTITION — okamžité smazání

-- Smazat všechna data za prosinec 2025
ALTER TABLE bets DROP PARTITION '202512';

-- Smazat data starší 90 dnů (dynamicky)
-- Nejprve vypočítáme název partitiony před 90 dny od dneška
ALTER TABLE bets DROP PARTITION toYYYYMM(today() - interval 90 day);

Po tomto příkazu složka s particí zmizí z disku. Operace trvá milisekundy, bez ohledu na to, kolik řádků uvnitř bylo — milion nebo miliarda.

Proč je to bezpečné? Protože partitiony jsou izolované. Smazání jedné neovlivní ostatní.

DETACH PARTITION — dočasné odpojení

-- Odpojíme partici (data zůstávají na disku, ale nejsou dostupná pro SELECT)
ALTER TABLE bets DETACH PARTITION '202512';

Partitiona se přesune do podsložky detached. Neúčastní se dotazů, ale lze ji vrátit zpět.

Kdy je to potřeba:

  • Máš podezření, že data jsou poškozená, a chceš je dočasně skrýt.
  • Chceš zkopírovat partici na jiný server (ATTACH pak na novém místě).

ATTACH PARTITION — obnovení odpojené partitiony

-- Vrátíme partici zpět (pokud je ve složce detached)
ALTER TABLE bets ATTACH PARTITION '202512';

FREEZE PARTITION — okamžitá záloha

-- Vytvoříme záložní kopii partitiony prosinec 2025
ALTER TABLE bets FREEZE PARTITION '202512';

ClickHouse vytvoří pevné odkazy (hard links) na soubory partitiony ve složce shadow/. Není to kopírování dat (rychlé), ale pouze vytvoření dalších ukazatelů na stejné bloky na disku. Poté můžeš zkopírovat shadow na jiný server.

Proč je to lepší než běžná záloha? Protože není třeba zastavit zápis a nezabírá se místo duplikováním dat.

MOVE PARTITION — pro tiered storage

O tom podrobněji v sekci 6.

6. MOVE PARTITION — tiered storage (SSD → HDD → S3)

V ClickHouse lze nakonfigurovat více úložišť s různou cenou a rychlostí. Například:

  • Horká data (poslední měsíc) — na rychlých NVMe SSD
  • Teplá data (2–6 měsíců) — na běžných HDD
  • Studená data (starší 6 měsíců) — v cloudovém S3 (levné, ale pomalé)

Partitiony umožňují přesouvat data mezi těmito úrovněmi jedním příkazem.

Nastavení v config.xml (zjednodušeně):

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

Přesun partitiony z SSD na HDD:

-- Data za leden 2025 (už nepotřebujeme rychle) přesuneme na HDD
ALTER TABLE bets MOVE PARTITION '202501' TO VOLUME 'cold';

Co se stane: ClickHouse fyzicky přesune složku partitiony z SSD na HDD. SELECT bude nadále fungovat, ale bude o něco pomalejší (kvůli HDD). DROP PARTITION je stále rychlý.

Analogický příklad: Přesouváš staré složky z rychlé skříně vedle tebe do vzdálené archivní skříně. Přístup je možný, ale cesta je delší.

7. Partitionování podle více sloupců

Někdy je potřeba rozdělovat data nejen podle času, ale i podle jiné dimenze. Například máš multi-brandovou platformu (několik casin v jedné databázi). Chceš mazat stará data zvlášť pro každou značku a případně je ukládat na různé disky.

-- Tabulka sázek pro 5 značek, partitiony podle měsíce A značky
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)   -- Dva sloupce!
ORDER BY (brand_id, user_id, created_at);

Jak to funguje:

  • Každá unikátní kombinace (rok+měsíc, brand_id) se stává samostatnou particí.
  • Pro prosinec 2025 a značku 1 — partition ('202512', 1).
  • Pro prosinec 2025 a značku 2 — partition ('202512', 2).

Proč je to užitečné:

  • DROP PARTITION může smazat data konkrétní značky za konkrétní měsíc.
  • MOVE PARTITION může přesunout stará data značky A na HDD, zatímco data značky B (prémiové) ponechat na SSD.

Jak smazat partici pro konkrétní značku:

-- Smažeme data casino_A za prosinec 2025
ALTER TABLE bets_multi_brand DROP PARTITION ('202512', 1);

Ale je tu nuance: Název partitiony je nyní tuple. Při prohlížení v system.parts bude vypadat jako ('202512', '1'). To je normální.

8. Jak partitionování ovlivňuje výkon

Vliv na INSERT

Při vkládání dat se ClickHouse podívá na výraz PARTITION BY a nasměruje řádek do příslušné partitiony. Pokud máš 1000 particí — je to rychlé. Pokud 100 000 — každé vkládání musí určit správnou složku, což zpomaluje zápis.

Co se stane, když jsou v jednom INSERT řádky z různých particí? ClickHouse je rozdělí do různých složek — to je normální, ale o něco pomalejší, než kdyby všechny řádky byly z jedné partitiony.

Rada: Pokud vkládáš data po dávkách (např. jednou za minutu), snaž se, aby v jedné dávce byly řádky za krátký časový úsek. Pak spadnou do jedné až dvou particí a vkládání bude rychlejší.

Vliv na SELECT

Partitionování zrychluje SELECT pouze pokud je v WHERE podmínka na sloupec partitionování. ClickHouse používá partitiony pro hrubé odfiltrování: podívá se, které partitiony jsou potřeba, a čte pouze jejich složky.

-- RYCHLE: partition odfiltruje všechna data mimo prosinec 2025
SELECT count() FROM bets 
WHERE created_at BETWEEN '2025-12-01' AND '2025-12-31';

-- POMALU: partition se nepoužije, skenujeme všechny partitiony
SELECT count() FROM bets 
WHERE amount > 1000;   -- žádný filtr podle created_at

Proč není vždy nutné partitionovat velmi jemně? Protože:

  • Čtení z 1000 malých particí (např. po dnech za 3 roky) může být pomalejší než z 36 velkých (po měsících), pokud dotaz pokrývá velký rozsah. ClickHouse otevírá jeden souborový deskriptor na partici.
  • Indexy (primární klíč) jsou často účinnější než jemné partitionování.

Empirické pravidlo: Nejdříve optimalizuj ORDER BY (index), poté partitionování. Partitiony slouží ke správě dat (DROP, MOVE), nejen ke zrychlení SELECT.

9. Typická chyba: příliš detailní partitionování

To je nejčastější bolest začátečníků v ClickHouse.

Příklad špatného přístupu:

-- ŠPATNĚ: partition podle dnů pro tabulku s 10 miliony řádků denně
CREATE TABLE logs_bad
(
    created_at DateTime,
    message String
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(created_at)   -- Pozor!
ORDER BY created_at;

Za 3 roky vznikne 365 * 3 = 1095 particí. To je ještě únosné (ale už na hraně). Za 10 let — 3650 particí, což je špatně. Systém začne zpomalovat.

Ještě horší — po hodinách pro data se zátěží 1 milion záznamů za hodinu: Za rok 8760 particí. Při každém vkládání bude ClickHouse hledat nebo vytvářet složku pro aktuální hodinu. SELECT * FROM system.parts začne trvat sekundy. Slučování na pozadí se bude dusit.

Příznaky, že máš příliš mnoho particí:

  1. Dotaz SELECT * FROM system.parts WHERE table = 'mytable' trvá déle než 1 sekundu.
  2. V logech ClickHouse se objevují varování: Too many parts (300+).
  3. ALTER TABLE ... DROP PARTITION netrvá milisekundy, ale několik sekund.

Co dělat, pokud už jsi napartitionoval příliš jemně? Lze sloučit partitiony pomocí ALTER TABLE ... MODIFY PARTITION BY ..., ale je to složité. Jednodušší je vytvořit novou tabulku se správným partitionováním, přelít data a přejmenovat.

10. Skript pro automatické mazání starých particí

V praxi potřebuješ uchovávat data například jen za posledních 90 dní. Připomínat si každý měsíc mazat staré partitiony není řešení. Je potřeba automatizace.

Varianta 1: Periodický dotaz přes cron nebo Task

-- Smažeme všechny partitiony starší 90 dnů
-- Spouštět jednou denně ve 3:00 ráno
ALTER TABLE bets DROP PARTITION WHERE partition < toYYYYMM(today() - interval 90 day);

Jak to funguje:

  • toYYYYMM(today() - interval 90 day) — vypočítá název partitiony pro datum před 90 dny. Například pokud je dnes 2026-06-11, pak před 90 dny je 2026-03-13, toYYYYMM202603.
  • partition < 202603 — smaže všechny partitiony s názvy 202602, 202601, 202512 atd.

Důležité: Tento dotaz funguje pouze pokud jsou názvy particí čísla (rok+měsíc). Pro řetězcové názvy (např. '2025-12') je potřeba jiné porovnání.

Varianta 2: Bezpečnější skript přes uložené seznamy

-- Najdeme seznam particí starších N dnů
SELECT partition
FROM system.parts
WHERE table = 'bets' 
  AND active = 1
  AND toDate(parseDateTimeBestEffort(partition)) < today() - interval 90 day
GROUP BY partition;

-- Pro každou nalezenou partici provedeme DROP (z externího skriptu, ne přímo v SQL)

Proč bys neměl dělat DROP PARTITION WHERE partition < ... s dynamickým výpočtem? Protože pokud jsou v tabulce partitiony s nestandardními názvy (např. 'all' nebo ručně vytvořené), podmínka může fungovat neočekávaně. Lepší je nejprve se podívat na seznam.

Kompletní příklad skriptu pro Bash / Python:

#!/bin/bash
# Mažeme partitiony starší 90 dnů pro tabulku bets

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

# Vypočítáme hraniční datum
BORDER_DATE=$(date -d "today - $DAYS_TO_KEEP days" +%Y%m)

# Získáme seznam particí starších hranice
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
")

# Smažeme každou partici
for PARTITION in $PARTITIONS; do
    echo "Mažu partici $PARTITION z tabulky $TABLE"
    $CLICKHOUSE_CLIENT --query="ALTER TABLE $TABLE DROP PARTITION '$PARTITION'"
done

Automatizace přes cron:

# Spouštění každý den ve 3:00
0 3 * * * /usr/local/bin/cleanup_clickhouse_partitions.sh >> /var/log/cleanup.log 2>&1

Co dál

Teď už chápeš, jak partitionování mění mazání dat z bolestivé operace na okamžitý úkon. Další témata:

  • Pokročilé strategie TTL (time-to-live) — automatické mazání nebo přesun řádků bez tvého zásahu.
  • Nastavení storage policies — jak udělat automatický MOVE particí z SSD na S3 podle plánu.
  • Optimalizace SELECT pomocí particí — jak psát dotazy, aby ClickHouse odfiltroval 99 % particí.

Shrnutí: Partitionování v ClickHouse je nástroj pro správu životního cyklu dat, nejen pro zrychlení dotazů. Velikost partitiony vybírej tak, aby jich bylo 100 až 1000 na server. Nedělej je příliš jemné, ani příliš hrubé. A vždy se dívej na system.parts — ta řekne pravdu.


Předchozí:
Další: ORDER BY a PRIMARY KEY v ClickHouse: jak nešlápnout vedle s indexem

— Editorial Team

Advertisement 728x90

Číst dál