ClickHouse — 열 지향 분석 DB 를 속까지 · 뮤테이션·경량 DELETE·TTL · 实验
파트를 다시 쓰는 수정, 가리는 삭제, 병합 때의 수명
목표
불변 파트 위에서 UPDATE·DELETE·TTL 이 실제로 무엇을 하는지 system.mutations·system.part_log·system.parts 로 확인하고, 멈춘 뮤테이션을 찾아 끝낸다.
왜 중요한가
ClickHouse 에서 UPDATE 한 줄은 파트 전체를 다시 쓰는 일이고, 경량 DELETE 는 행을 가릴 뿐이며, TTL 은 병합이 올 때까지 기다립니다. 이 차이를 모르면 작은 정정이 디스크 I/O 폭주가 되고, 지웠다고 믿은 행이 디스크에 남고, 실패한 뮤테이션 하나가 표의 모든 수정을 막습니다. 이 실습의 채점기는 여러분이 적은 숫자를 믿지 않습니다 — 원본 생성 식으로 남아 있어야 할 행을 다시 계산하고, 가림막을 끈 채(apply_deleted_mask = 0)로도 세고, system.part_log 의 기록과 대조합니다.
단계
1. 데이터베이스 mut 와 표 mut.events 를 만드세요 — 열 event_date Date, ts DateTime, user_id UInt32, email String, amount UInt32, status LowCardinality(String), legal_hold UInt8 (이 순서), MergeTree, ORDER BY (user_id, ts). /opt/lab/fixtures/mutation/events.sql 로 40만 행을 한 번 넣고 OPTIMIZE TABLE mut.events FINAL 로 파트를 하나로 만드세요.
2. ALTER TABLE mut.events UPDATE status = 'refunded' WHERE status = 'refund_req' 를 mutations_sync = 2 로 실행하고, 그 mutation_id, 전후의 활성 파트 이름(part_before·part_after), system.part_log 의 그 MutatePart 가 쓴 행 수(rows_rewritten)를 /root/ch/mutation/mutation.json 에 적으세요.
3. user_id = 777 의 행을 ALTER TABLE ... DELETE 로 지우세요(mutations_sync = 2).
4. user_id = 888 의 행을 경량 DELETE(DELETE FROM)로 지우세요. 곧바로 보통 SELECT 로 센 그 사용자의 행(visible_rows), SETTINGS apply_deleted_mask = 0 으로 센 행(masked_rows), system.parts 의 활성 파트 rows(part_rows)를 /root/ch/mutation/lwd.json 에 적은 뒤 OPTIMIZE TABLE mut.events FINAL 을 실행하세요.
5. email 열에 TTL if(legal_hold = 1, toDate('2100-01-01'), event_date + INTERVAL 90 DAY) 를 붙이고(MODIFY COLUMN email String TTL ...), 기존 파트에 적용하세요.
6. 표 TTL event_date + INTERVAL 180 DAY DELETE WHERE status = 'test' 를 붙이고(MODIFY TTL), 기존 파트에 적용하세요.
7. 표 mut.hits (ts DateTime, user_id UInt32, hits UInt32, max_hits UInt32 DEFAULT hits, sum_hits UInt64 DEFAULT hits) 를 MergeTree, PRIMARY KEY (user_id, toStartOfDay(ts), ts), TTL ts + INTERVAL 30 DAY GROUP BY user_id, toStartOfDay(ts) SET max_hits = max(max_hits), sum_hits = sum(sum_hits) 로 만들고, /opt/lab/fixtures/mutation/hits.sql 을 한 번 넣은 뒤 OPTIMIZE TABLE mut.hits FINAL 로 요약을 적용하세요.
8. ALTER TABLE mut.events UPDATE amount = toUInt32(email) WHERE legal_hold = 1 을 (기다리지 않고) 제출하고, 실패가 기록되면 그 뮤테이션의 mutation_id·is_done·parts_to_do·latest_fail_error_code_name(열쇠 error_code_name)을 /root/ch/mutation/stuck.json 에 적은 뒤 KILL MUTATION 으로 끝내세요.
참고
- 뮤테이션 확인:
SELECT mutation_id, command, is_done, parts_to_do, latest_fail_reason FROM system.mutations WHERE database = 'mut'. - 파트가 어떻게 다시 쓰였는지:
SYSTEM FLUSH LOGS뒤SELECT event_type, part_name, merged_from, rows FROM system.part_log WHERE database = 'mut' ORDER BY event_time_microseconds. - TTL 은 병합 때 적용됩니다. 지금 적용하려면
ALTER TABLE ... MATERIALIZE TTL SETTINGS mutations_sync = 2나OPTIMIZE TABLE ... FINAL. - 흔한 실수: 4단계에서 OPTIMIZE 를 먼저 쳐 가림막 상태를 놓치는 것, 6단계의 WHERE 를 빠뜨려 180일 지난 모든 행(=전부)을 지우는 것, 8단계에서 KILL 을 잊어 뒤의 모든 뮤테이션이 막히는 것.
- 픽스처는 2024년 자료입니다. 망가뜨렸다면
DROP DATABASE mut뒤 1단계부터 다시 하는 것이 가장 빠릅니다. - 공식 문서: [Avoid mutations](https://clickhouse.com/docs/concepts/best-practices/avoid-mutations) · [ALTER TABLE ... UPDATE](https://clickhouse.com/docs/reference/statements/alter/update) · [ALTER TABLE ... DELETE](https://clickhouse.com/docs/reference/statements/alter/delete) · [Lightweight delete](https://clickhouse.com/docs/concepts/features/operations/delete/lightweight-delete) · [Manage data with TTL](https://clickhouse.com/docs/concepts/features/operations/delete/ttl) · [ALTER TABLE ... MODIFY TTL](https://clickhouse.com/docs/reference/statements/alter/ttl) · [system.mutations](https://clickhouse.com/docs/reference/system-tables/mutations) · [system.part_log](https://clickhouse.com/docs/reference/system-tables/part_log)
8个步骤
- 파트 하나짜리 이벤트 표
- 2% 를 바꾸려고 파트 전체를 쓴다
- 무거운 삭제 — ALTER TABLE ... DELETE
- 경량 DELETE 는 가릴 뿐이다
- 열 TTL — 기한 지난 값만 지운다
- 행 TTL — 조건에 맞는 행만 지운다
- GROUP BY TTL — 오래된 행을 요약으로
- 멈춘 뮤테이션을 찾아 끝낸다