ClickHouse — 열 지향 분석 DB 를 속까지 · 열로 저장한다는 것 · 实验
200만 행을 넣고 열 파일을 들여다본다
목표
MergeTree 표에 200만 행을 넣고, 파트·그래뉼·열별 압축률을 system 표에서 읽는다. 같은 행 수를 읽어도 건드린 열과 정렬 키에 따라 비용이 달라지는 것을 rows_read·bytes_read 로 확인한다.
왜 중요한가
열 지향 DB 에서 쿼리 비용은 "몇 행을 골랐나" 가 아니라 "어느 열을 몇 그래뉼 읽었나" 로 정해진다. 이 감각이 없으면 정렬 키를 잘못 고르고, SELECT * 를 습관처럼 쓰고, 디스크 용량을 원본 크기로 잡는다. 이 실습의 채점기는 여러분이 적은 숫자를 믿지 않는다 — 서버의 system.parts·system.columns·system.query_log 를 직접 읽고, 여러분이 저장한 SELECT 를 읽기 전용으로 다시 돌려 읽은 행·바이트를 재서 대조한다. 채점기 자신의 쿼리는 query_log 에 남지 않는다.
단계
1. 데이터베이스 col 과 표 col.events 를 만드세요 — 열 ts DateTime, site LowCardinality(String), user_id UInt64, url String, dur_ms UInt32, country FixedString(2) (이 순서), 엔진 MergeTree, 정렬 키 ORDER BY (site, ts).
2. /opt/lab/fixtures/columnar/events.sql 을 한 번 실행해 200만 행을 넣으세요.
3. OPTIMIZE TABLE col.events FINAL 로 파트를 하나로 합친 뒤, 그 파트의 part(이름)·rows·marks·part_type 을 /root/ch/columnar/parts.json 에 적으세요.
4. system.columns 에서 비압축/압축 비율이 가장 큰 열(most_compressed)·가장 작은 열(least_compressed)·압축 후 바이트 합(total_compressed_bytes)을 /root/ch/columnar/columns.json 에 적으세요.
5. dur_ms 의 합만 구하는 /root/ch/columnar/q_one.sql 과 url 문자열의 내용을 읽는 /root/ch/columnar/q_url.sql(예: max(url))을 만들고, 두 쿼리의 bytes_read 를 /root/ch/columnar/bytes.json 에 one_col_bytes·url_bytes 로 적으세요.
6. site = 'docs.example' 인 행의 dur_ms 합을 내는 /root/ch/columnar/q_key.sql 과 country = 'KR' 인 행의 dur_ms 합을 내는 /root/ch/columnar/q_nokey.sql 을 만들고, 두 쿼리의 rows_read 를 /root/ch/columnar/rows.json 에 key_rows_read·nokey_rows_read 로 적으세요.
7. SELECT uniqExact(user_id) FROM col.events WHERE site = 'shop.example' 을 SETTINGS log_comment = 'chs-col-07' 을 붙여 돌린 뒤, system.query_log 에서 그 쿼리를 찾아 query_id·read_rows·read_bytes·result_rows 를 /root/ch/columnar/qlog.json 에 적으세요.
8. col.events 와 같은 열의 표 col.small 을 만들어 col.events 의 1000행을 INSERT 한 번으로 넣고, 두 표의 파트 형식을 /root/ch/columnar/part_types.json 에 events·small 로 적으세요.
참고
- 서버는 파드가 뜰 때 이미 떠 있습니다(127.0.0.1:9000).
clickhouse-client만 치면 붙습니다. 멈췄다면ch-up. - 파일로 쿼리 돌리기:
clickhouse-client --queries-file 파일.sql. 결과 끝의 통계는--format JSON으로 받으면statistics에 있습니다(jq .statistics). - 숫자를 JSON 에 따옴표 없이 받으려면
--output_format_json_quote_64bit_integers 0을 줍니다. OPTIMIZE ... FINAL은 실습에서 파트 수를 고정하려고 쓰는 것입니다. 운영에서는 병합을 서버에 맡기는 것이 원칙입니다.- query_log 는 약 1초마다 비워집니다. 방금 돌린 쿼리가 안 보이면
SYSTEM FLUSH LOGS. - 흔한 실수: 2단계를 두 번 돌려 400만 행이 되는 것 — MergeTree 는 중복을 막지 않습니다. 그때는
TRUNCATE TABLE col.events뒤 다시 넣습니다. - 공식 문서: [Table parts](https://clickhouse.com/docs/concepts/core-concepts/parts) · [Primary indexes](https://clickhouse.com/docs/concepts/core-concepts/primary-indexes) · [MergeTree](https://clickhouse.com/docs/reference/engines/table-engines/mergetree-family/mergetree) · [system.parts](https://clickhouse.com/docs/reference/system-tables/parts) · [system.columns](https://clickhouse.com/docs/reference/system-tables/columns) · [system.query_log](https://clickhouse.com/docs/reference/system-tables/query_log)
8个步骤
- 정렬 키가 있는 MergeTree 표를 만든다
- 원본 200만 행을 넣는다
- 파트를 하나로 합치고 이름을 읽는다
- 열마다 압축률이 얼마나 다른가
- 같은 행, 다른 열 — 읽은 바이트
- 정렬 키로 거를 때만 건너뛴다
- query_log 에서 자기 쿼리를 찾는다
- 작은 파트는 Compact 가 된다