LabHub
배우기 러닝패스 코스

ClickHouse — 열 지향 분석 DB 를 속까지 · SummingMergeTree 와 AggregatingMergeTree · 실습

요약 표를 나눠 넣고, 합과 상태로 원본과 같은 답을 낸다

LabHub 에서 이어서 보기

목표

원본 이벤트에서 (site, day) 요약을 SummingMergeTree 와 AggregatingMergeTree 에 나눠 넣고, 병합 전에도 원본과 똑같은 답을 내는 조회를 씁니다. 합으로 줄일 수 없는 값은 상태로 담아야 한다는 것과 그 상태를 더 큰 단위로 다시 합치는 법을 확인합니다.

왜 중요한가

요약 표는 대시보드를 싸게 만들지만, 병합이 끝나기 전에는 같은 키가 여러 행으로 흩어져 있습니다. 그 상태에서 SELECT * 로 읽거나, 서로 다른 사용자 수를 숫자로 저장해 더하면 틀린 답이 조용히 나옵니다. 이 실습은 병합을 멈춰 그 틀린 상태를 고정하고, 채점기가 여러분의 쿼리 결과를 원본 agg.hits 를 직접 집계한 값과 칸마다 대조합니다. 몇 번에 나눠 넣었는지는 system.part_log 기록으로 확인합니다.

단계

1. 데이터베이스 agg 와 표 agg.hits 를 만드세요 — 열 ts DateTime, site LowCardinality(String), user_id UInt64, dur_ms UInt32, is_bot UInt8(이 순서), 엔진 MergeTree, ORDER BY (site, ts).
2. /opt/lab/fixtures/aggregating/hits.sql한 번 실행해 100만 행을 넣으세요.
3. agg.daily (site LowCardinality(String), day Date, hits UInt64, dur_total UInt64)ENGINE = SummingMergeTree ORDER BY (site, day) 로 만들고 SYSTEM STOP MERGES agg.daily 로 병합을 멈춘 뒤, agg.hits 를 시간대별(toHour(ts) < 8, 8 이상 16 미만, 16 이상)로 INSERT 세 번에 나눠 site, toDate(ts), count(), sum(dur_ms) 를 넣으세요.
4. 병합 전인 지금도 원본과 같은 (site, day)별 조회수·체류 합을 내는 /root/ch/aggregating/q_daily.sql 을 만드세요(agg.daily 만 읽고, 열은 site, day, hits, dur_total 순서). 그리고 agg.daily 의 지금 행 수와 서로 다른 (site, day) 수를 /root/ch/aggregating/raw.jsonraw_rows·keys 로 적으세요.
5. SYSTEM START MERGES agg.dailyOPTIMIZE TABLE agg.daily FINAL 로 합쳐, 키마다 한 행이 되게 하세요.
6. agg.daily_state (site LowCardinality(String), day Date, users AggregateFunction(uniqExact, UInt64), avg_dur AggregateFunction(avg, UInt32), human_hits AggregateFunction(countIf, UInt8))ENGINE = AggregatingMergeTree ORDER BY (site, day) 로 만들고 병합을 멈춘 뒤, 3단계와 같은 시간대 세 묶음으로 uniqExactState(user_id)·avgState(dur_ms)·countIfState(is_bot = 0) 을 넣으세요.
7. agg.daily_state 만 읽어 (site, day)별 users·avg_dur·human_hits 를 내는 /root/ch/aggregating/q_state.sql 을 만드세요(열은 site, day, users, avg_dur, human_hits 순서). 그리고 병합 전 각 행의 finalizeAggregation(users) 를 그냥 더한 값과 q_state.sql 의 users 를 모두 더한 값을 /root/ch/aggregating/naive.jsonnaive_users_sum·true_users_sum 으로 적으세요.
8. agg.day_total (day Date, users AggregateFunction(uniqExact, UInt64))ENGINE = AggregatingMergeTree ORDER BY day 로 만들어 agg.daily_state 의 상태를 uniqExactMergeState(users) 로 날짜별로 다시 합쳐 넣고, agg.day_total 만 읽어 날짜별 (사이트 구분 없는) 서로 다른 사용자 수를 내는 /root/ch/aggregating/q_day.sql 을 만드세요(열은 day, users).

참고

8단계

  1. 원본 이벤트 표
  2. 원본 100만 행
  3. SummingMergeTree 에 세 번 나눠 넣는다
  4. 병합 전에도 맞는 조회
  5. 병합하면 키마다 한 행
  6. 합으로 줄일 수 없는 값은 상태로
  7. 상태는 합친 뒤에 끝낸다
  8. 상태를 더 큰 단위로 다시 합친다