TTL v ClickHouse: Automatické řízení životního cyklu dat
1. Proč je TTL potřeba – problém „zapomněl jsem smazat“
Vraťme se k našemu online casinu. Ukládáš všechny sázky hráčů. Za měsíc má tabulka 500 GB. Za rok – 5 TB. Disky se plní, dotazy zpomalují a stará data jsou potřeba čím dál méně. Majitel firmy říká: „Hráči se dívají jen na posledních 30 dní sázek a pro reporty potřebujeme jen agregovaný součet za stará období.“
Můžeš napsat skript, který jednou denně smaže staré partitiony (jak jsme se učili v článku o partitionování). To ale vyžaduje externí plánovač (cron), samostatný skript, monitorování jeho běhu a zpracování chyb.
TTL (Time-To-Live – „doba života“) řeší tento problém na úrovni databáze. Je to vestavěný mechanismus ClickHouse, který automaticky:
- maže staré řádky,
- přesouvá je na levnější disky (HDD, S3),
- agreguje stará data (sbalí detaily do souhrnů),
- anonymizuje osobní údaje (GDPR).
To vše probíhá na pozadí, bez tvého zásahu, podle plánu, který nastavíš v SQL.
Analogický příklad z reálného života: TTL je jako pronájem skladovacího prostoru. Domluvíš se s majitelem: „Zboží, které leží déle než 30 dní, přesuň do vzdáleného levného oddílu. Pokud leží déle než rok, vyhoď.“ Majitel sám hlídá termíny a dělá práci, nemusíš mu to neustále připomínat.
2. TTL na úrovni řádků – mazání starých záznamů
Nejjednodušší varianta: řádky žijí určitou dobu, pak jsou smazány.
CREATE TABLE s TTL
-- Vytvoříme tabulku sázek, kde řádky žijí 90 dní
CREATE TABLE bets
(
user_id UInt64,
amount Decimal(18,2),
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY (user_id, created_at)
TTL created_at + INTERVAL 90 DAY; -- Po 90 dnech od created_at je řádek smazán
Co se zde děje:
TTL created_at + INTERVAL 90 DAY– pro každý řádek se vypočítá datum vypršení:created_at+ 90 dní. Jakmile aktuální datum (today()) překročí toto datum, řádek je označen k smazání.- Proces na pozadí (obvykle jednou denně) prochází granule a maže řádky s vypršeným TTL.
- Mazání probíhá na úrovni partů (parts) – ClickHouse přepíše part bez smazaných řádků.
ALTER TABLE – přidání nebo změna TTL
Hlavní výhoda: TTL lze přidat k existující tabulce bez jejího přetvoření.
-- Přidáme TTL k existující tabulce
ALTER TABLE bets MODIFY TTL created_at + INTERVAL 90 DAY;
-- Změníme dobu života z 90 na 180 dní
ALTER TABLE bets MODIFY TTL created_at + INTERVAL 180 DAY;
-- Odebereme TTL (data budou uložena navždy)
ALTER TABLE bets REMOVE TTL;
Proč je to důležité? Protože v reálném životě se požadavky na ukládání mění. Nejdřív sis myslel, že je potřeba ukládat všechno navždy. Pak se ukázalo, že zálohy zabírají místo a analytici stará data nepotřebují. S MODIFY TTL změníš pravidlo jedním řádkem.
Co se stane, když přidáš TTL na tabulku s 10 miliardami řádků? Nic hrozného. ClickHouse nebude přepisovat data okamžitě. Prostě začne TTL aplikovat na pozadí, postupně. Při příštím sloučení partů budou staré řádky vyřazeny.
3. TTL s přesunem na jiný disk (tiered storage)
Někdy je škoda data mazat, ale ukládat je na rychlých drahých SSD je nákladné. Řešení: přesouvat stará data na pomalé levné HDD (nebo do cloudového úložiště S3).
Nejprve nastavíme disky v konfiguraci ClickHouse (config.xml):
<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>
Nyní vytvoříme tabulku s TTL přesunem:
CREATE TABLE bets_tiered
(
user_id UInt64,
amount Decimal(18,2),
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY (user_id, created_at)
TTL created_at + INTERVAL 30 DAY TO DISK 'hdd'; -- Po 30 dnech se přesune na HDD
Co se stane: Řádky žijí na rychlém SSD prvních 30 dní (kdy jsou nejčastěji potřeba v reportech). Po 30 dnech ClickHouse na pozadí přesune party dat na HDD. Při dotazu na stará období budou data dostupná, ale o něco pomalejší.
Lze kombinovat – nejprve přesunout, pak smazat:
-- 30 dní na SSD, pak na HDD do 90 dní, pak smazat
CREATE TABLE bets_multi_ttl
(
user_id UInt64,
amount Decimal(18,2),
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY user_id
TTL
created_at + INTERVAL 30 DAY TO DISK 'hdd',
created_at + INTERVAL 90 DAY DELETE;
Analogický příklad: Hotel: prvních 30 dní bydlíš v luxusním apartmá (rychlé, drahé). Pak tě přestěhují do standardního pokoje (pomalejší, levnější). A po 90 dnech tě vystěhují. Vše automaticky.
4. TTL s přesunem na S3
ClickHouse umí pracovat s cloudovými úložišti (Amazon S3, MinIO, Google Cloud Storage). Můžeš nastavit storage_policy s S3 a přesouvat stará data do cloudu, kde je ukládání levné.
Nastavení (zjednodušeně):
<storage_configuration>
<disks>
<s3>
<type>s3</type>
<endpoint>https://s3.amazonaws.com/mybucket/clickhouse/</endpoint>
<access_key_id>AKIAIOSFODNN7EXAMPLE</access_key_id>
<secret_access_key>wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY</secret_access_key>
</s3>
</disks>
<policies>
<s3_policy>
<volumes>
<hot>
<disk>default</disk> <!-- lokální SSD -->
</hot>
<cold_s3>
<disk>s3</disk> <!-- cloud -->
</cold_s3>
</volumes>
</s3_policy>
</policies>
</storage_configuration>
Tabulka s TTL do S3:
CREATE TABLE bets_s3
(
user_id UInt64,
amount Decimal(18,2),
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY created_at
TTL created_at + INTERVAL 90 DAY TO VOLUME 'cold_s3'; -- po 90 dnech do S3
Proč je to skvělé: Platíš za S3 haléře za gigabajt měsíčně. Data zůstávají dostupná pro analýzu (i když pomaleji než z lokálního disku). Přitom se nemusíš starat o nedostatek místa na serveru – S3 je nekonečné.
5. TTL pro agregaci (nejsilnější funkce)
Toto je můj oblíbený vzor. Místo mazání starých detailních dat je sbalíš do agregátů. Například sázky starší 7 dní nepotřebuješ v rozlišení každé sekundy, ale potřebuješ součty po dnech a uživatelích.
-- Tabulka s detailními sázkami
CREATE TABLE bets_detailed
(
user_id UInt64,
bet_id String,
amount Decimal(18,2),
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY (user_id, created_at)
TTL created_at + INTERVAL 7 DAY
GROUP BY toDate(created_at) AS day, user_id
SET total_bets = sum(amount), -- součet všech sázek za den
bet_count = count() -- počet sázek za den
DELETE WHERE day < now() - INTERVAL 90 DAY; -- po 90 dnech smažeme i agregáty
Rozebíráme po částech:
TTL created_at + INTERVAL 7 DAY– po 7 dnech od vytvoření řádku (detailní sázky) přestává být detailní.GROUP BY toDate(created_at) AS day, user_id– řádky se seskupí podle dne a uživatele. Místo tisíců detailních sázek za den pro jednoho uživatele bude jeden agregovaný řádek.SET total_bets = sum(amount), bet_count = count()– v novém agregovaném řádku se pole vyplní agregačními funkcemi.DELETE WHERE day < now() - INTERVAL 90 DAY– agregáty starší 90 dní se definitivně smažou.
Co se stane v praxi:
- Den 0–7: Data leží v detailní podobě. Můžeš analyzovat každou sázku.
- Den 7–90: Detailní sázky se sbalí do řádku na
(user_id, day)s politotal_betsabet_count. Místa je 10–100krát méně. - Den 90+: I agregáty se smažou, zůstanou jen zálohy.
Analogický příklad: Píšeš si deník se záznamy každou hodinu. Po týdnu přepíšeš hodinové záznamy do denních souhrnů. A po třech měsících vyhodíš i denní souhrny a necháš jen měsíční reporty.
6. TTL pro konkrétní sloupce (GDPR anonymizace)
Podle zákona (GDPR v Evropě, osobní údaje) jsi povinen uchovávat osobní informace (e-mail, IP adresu) jen po určitou dobu. Anonymní analytiku (součet sázek, počet her) můžeš uchovávat navždy.
TTL lze aplikovat ne na celý řádek, ale na jednotlivé sloupce.
-- Tabulka s osobními údaji
CREATE TABLE user_events
(
user_id UInt64,
email String, -- osobní sloupec
ip_address String, -- osobní sloupec
event_type String,
event_value UInt64,
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY (user_id, created_at)
TTL
email + INTERVAL 1 YEAR, -- po roce se email vynuluje
ip_address + INTERVAL 1 YEAR, -- po roce se IP vynuluje
created_at + INTERVAL 10 YEAR; -- po 10 letech se smaže celý řádek
Co se stane: Rok po vytvoření řádku budou sloupce email a ip_address nahrazeny výchozími hodnotami (prázdný řetězec pro String, 0 pro čísla). Data zůstanou užitečná pro analýzu (víš, že existoval nějaký uživatel, ale nevíš kdo přesně). Po 10 letech se smaže celý řádek.
Proč je to důležité pro GDPR: Splňuješ požadavek zákona automaticky, bez ručních skriptů. Auditor může přijít, podívat se na tvá TTL pravidla a ujistit se, že osobní údaje nejsou uchovávány déle, než je povoleno.
7. Nastavení procesu na pozadí TTL
TTL nefunguje okamžitě po vypršení lhůty. ClickHouse spouští proces na pozadí, který:
- kontroluje granule,
- aplikuje TTL pravidla,
- přepisuje party bez zastaralých dat nebo se změněnými sloupci.
Parametry nastavení (v config.xml nebo pomocí SET):
-- Interval mezi spuštěními TTL procesu (výchozí 1 den)
ALTER SYSTEM MODIFY SETTING merge_with_ttl_timeout = 86400; -- v sekundách
-- Pro testování lze nastavit častěji
SET merge_with_ttl_timeout = 3600; -- každou hodinu
Proč by TTL nemělo být příliš časté? Protože aplikace TTL je operace přepisování partů dat, zatěžuje CPU a disky. Každý den je normální. Každou hodinu už může vadit, pokud máš terabajty dat.
Jak zkontrolovat, že TTL funguje:
-- Podíváme se, pro které party je TTL aktivní
SELECT
partition,
name,
rows,
modification_time,
has_ttl_info -- 1 = na tento part byl aplikován TTL
FROM system.parts
WHERE table = 'bets' AND active = 1;
8. MATERIALIZE TTL – vynucená aplikace
Někdy je potřeba, aby se TTL aplikovalo okamžitě, nečekat na proces na pozadí. Například:
- Právě jsi přidal TTL na obrovskou tabulku a chceš ihned vyčistit stará data.
- Testuješ TTL pravidla a nechceš čekat den.
-- Vynuceně aplikujeme TTL na celou tabulku
ALTER TABLE bets MATERIALIZE TTL;
-- Pouze pro konkrétní partition (rychlejší)
ALTER TABLE bets MATERIALIZE TTL IN PARTITION '202501';
Co se stane: ClickHouse prohledá všechny party tabulky (nebo partition) a okamžitě aplikuje všechna TTL pravidla. Může to trvat minuty nebo hodiny u velkých tabulek. Nedělej to ve špičce.
Kdy použít: V noci, během údržby nebo před vytvořením zálohy, aby se nezálohovala zbytečně mrtvá data.
9. Reálný use case: casino s GDPR a agregáty
Teď to dáme všechno dohromady. Představ si kompletní schéma ukládání událostí v online casinu.
-- Surové události (každá sázka, každá hra)
CREATE TABLE raw_events
(
user_id UInt64,
session_id String,
ip_address String, -- GDPR-sensitive
event_type String, -- 'bet', 'win', 'login'
event_value Int64,
created_at DateTime
)
ENGINE = MergeTree()
ORDER BY (user_id, created_at)
TTL
-- Detailní události uchováváme 30 dní
created_at + INTERVAL 30 DAY DELETE,
-- IP adresu mažeme po 14 dnech (GDPR)
ip_address + INTERVAL 14 DAY,
-- Agregace pro stará data: po 30 dnech sbalíme do denních souhrnů
created_at + INTERVAL 30 DAY
GROUP BY toDate(created_at) AS day, user_id
SET total_bets = sumIf(event_value, event_type = 'bet'),
total_wins = sumIf(event_value, event_type = 'win'),
sessions_count = countDistinct(session_id)
DELETE WHERE day < now() - INTERVAL 2 YEAR; -- agregáty uchováváme 2 roky
Co jsme získali:
- 0–14 dní: Plná informace včetně IP adres. Lze obnovovat incidenty, odhalovat multiaccounting.
- 15–30 dní: IP adresy jsou již vynulovány (anonymizovány), ale detailní události stále existují. Lze analyzovat chování uživatelů bez vazby na geolokaci.
- 31 dní – 2 roky: Detailní události smazány. Místo nich agregované řádky na
(den, uživatel). Místa je 100krát méně. Dashboardy fungují rychle. - Starší než 2 roky: Vše smazáno. Pouze zálohy na S3 (pokud je děláš).
Jak číst agregovaná data po TTL:
-- Nyní je v tabulce mix: detailní řádky (prvních 30 dní) a agregáty (do 2 let)
-- Stejně píšeš běžnou agregaci, která funguje na oba typy řádků
SELECT
toDate(created_at) AS day,
user_id,
sum(event_value) AS total
FROM raw_events
WHERE created_at >= today() - 45
GROUP BY day, user_id;
ClickHouse si sám poradí: pro čerstvá data sečte detailní řádky, pro stará použije hotové agregáty. Magie.
10. Kdy TTL NEPOUŽÍVAT a alternativy
Kdy TTL není vhodné:
Data se často aktualizují. TTL se spouští při vložení, ne při poslední aktualizaci. Pokud měníš řádek pomocí
INSERTse zrušením (CollapsingMergeTree), TTL bude počítat od původníhocreated_at. Řešení: použít sloupecupdated_atve výrazu TTL.Potřebuješ přesné řízení času. TTL proces je na pozadí a není přesný. Pokud potřebuješ zaručeně smazat řádek přesně o půlnoci – nepůjde. Rozptyl může být až několik hodin.
Velmi velké tabulky s řídkými mergemi. TTL se aplikuje během slučování partů. Pokud se tabulka slučuje zřídka (např. kvůli nastavení
merge_with_ttl_timeout), stará data mohou viset déle.
Alternativy k TTL:
| Přístup | Kdy použít | Výhody | Nevýhody |
|---|---|---|---|
| Partitionování + DROP PARTITION | Data přicházejí kontinuálně, mazání podle kalendáře | Okamžité smazání, žádná režie | Potřebuje externí plánovač, není flexibilní (jen podle partition) |
| TTL DELETE | Data mohou přicházet se zpožděním, mazání podle stáří řádku | Vestavěné, flexibilní, nevyžaduje externí skripty | Nepřesný čas mazání, zátěž na merge |
| TTL TO DISK | Potřeba uchovat data, ale na levném médiu | Úspora úložiště, transparentní pro dotazy | Vyžaduje nastavení storage_policy |
| TTL GROUP BY | Detailní data nejsou potřeba, jen agregáty | Výrazné snížení místa (100+ krát) | Ztráta detailů, složitější ladění |
Kombinuj s partitionováním pro lepší výsledky
Nejlepší praxe: používej partitionování + TTL dohromady.
CREATE TABLE bets_optimized
(
user_id UInt64,
amount Decimal(18,2),
created_at DateTime
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(created_at) -- partitiony po měsících
ORDER BY (user_id, created_at)
TTL created_at + INTERVAL 30 DAY DELETE; -- TTL po 30 dnech
Proč je to dobré:
- Partitiony pomáhají rychle mazat celé měsíce (pokud TTL zaostává).
- TTL čistí uvnitř partition flexibilněji (podle stáří řádku, ne podle kalendáře).
Co dál
Nyní ovládáš všechny nástroje automatického řízení dat v ClickHouse. Další témata:
- Pokročilé storage policies – jak nastavit automatický přesun z SSD → HDD → S3 s různými TTL v každé fázi.
- Monitorování TTL – jak pomocí system.query_log sledovat, kolik dat se maže a jak rychle.
- TTL + Materialized Views – jak automaticky agregovat stará data do samostatné tabulky, aniž by se mísila s detailními.
Shrnutí: TTL v ClickHouse je švýcarský nůž pro řízení životního cyklu dat. Umí mazat, přesouvat, agregovat a anonymizovat. Používej TTL ... DELETE pro čištění, TTL ... TO DISK pro úsporu, TTL ... GROUP BY pro magii s agregáty a TTL na sloupce pro GDPR. A nezapomínej na MATERIALIZE TTL, když potřebuješ pravidla aplikovat okamžitě.
← Předchozí: ORDER BY a PRIMARY KEY v ClickHouse: jak nešlápnout vedle s indexem
→ Další: Slovníky v ClickHouse: rychlý lookup bez JOIN
— Editorial Team
Zatím žádné komentáře.