시작하기 전에
1편에서 컬럼형 DB가 왜 빠른지를 이론으로 정리했었다. 필요한 컬럼만 읽고, 같은 타입이 모여 있어 압축이 잘 되고, Zone Map으로 블록을 건너뛰고, 단건 쓰기는 약하지만 벌크는 강하다는 식의 이야기들이었다.
이번 편에선 그게 실제로 그런지 직접 측정해봤다. MySQL과 ClickHouse를 같이 띄워서, 같은 데이터를 양쪽에 적재하고, 같은 쿼리를 던졌다. 결과는 1편 이론이 거의 그대로 입증된 부분이 많았고, 한두 가지는 미묘하게 어긋나기도 했다.
전체 코드와 스크립트는 GitHub repo에 올려뒀다. 직접 재현해보고 싶으면 그대로 돌려보면 된다.
시나리오 - 메트릭 모니터링
비교 시나리오는 1편 마지막에 다뤘던 메트릭 모니터링 으로 정했다. 데이터 모양이 시계열이라 직관적이고, 1편에서 이야기한 컬럼형의 장점이 가장 잘 드러나야 할 워크로드이기도 하다.
- 50대의 서버(
task-01~task-50)에서 10초마다 15가지 메트릭(cpu_user,mem_used,disk_read_bytes...) 을 수집 - 5개 region (
us-east,us-west,eu-west,ap-northeast,ap-southeast), 3개 env (prod40대 /staging8대 /dev2대) - 30일치 = 약 1억 9,400만 행 (
50 × 15 × 86400/10 × 30) - 보존 정책: 30일 후 삭제
데이터 분포는 현실에 가깝게 합성했다. cpu_user 같은 percentage 메트릭은 sin 파동에 노이즈를 더하고 가끔 spike 가 끼는 형태, disk_read_bytes 같은 bursty 메트릭은 대부분 작은 값에 가끔 큰 burst 가 섞이는 형태로 만들었다. 순수 random uniform 으로 채우면 압축률이 비현실적으로 좋게 나올 것 같아 일부러 피했다. 시드는 42 로 고정.
비교 대상 DB
Row DB 는 MySQL 8.0 (InnoDB). 컬럼형 DB 후보는 여러 개였다.
처음엔 Apache Cassandra 도 후보였는데, 찾아보니 이름에 column이 들어가 있어도 사실은 wide-column NoSQL 이고, 디스크 상에서 컬럼별 저장은 하지 않는다. Cassandra 의 "column-family" 는 Bigtable 계보에서 온 논리 모델 표현 (하나의 row 가 임의 개수의 column 을 가질 수 있다는 의미) 이지, 디스크 상에서 컬럼별로 묶어 저장한다는 뜻이 아니었다. 1편에서 다뤘던 압축·Zone Map·필요 컬럼만 읽기 같은 이론은 진짜 column-oriented DB (ClickHouse, Druid, DuckDB 등) 에만 해당한다.
그래서 2편은 ClickHouse 24.10 으로 진행했다. 메트릭 모니터링 도메인에서 Cloudflare·Uber·eBay 같은 회사들이 실제로 쓰고 있어 시나리오 적합성도 좋다. Cassandra 와의 비교는 3편으로 미뤘다.
두 DB의 스키마
같은 데이터를 두 DB 에 넣으려면 테이블을 만들어야 한다. 이 단계에서부터 차이가 꽤 컸다. DDL 이 단순히 문법만 다른 게 아니라, 컬럼형이라는 저장 모델 자체가 다른 DDL 을 요구한다는 점이 인상적이었다.
MySQL 스키마
CREATE TABLE metrics (
ts DATETIME(0) NOT NULL,
host VARCHAR(64) NOT NULL,
metric_name VARCHAR(64) NOT NULL,
region VARCHAR(16) NOT NULL,
env VARCHAR(16) NOT NULL,
value DOUBLE NOT NULL,
tags JSON DEFAULT NULL,
PRIMARY KEY (host, metric_name, ts),
INDEX idx_region_metric_ts (region, metric_name, ts),
INDEX idx_metric_ts (metric_name, ts)
)
ENGINE=InnoDB
PARTITION BY RANGE (TO_DAYS(ts)) (
PARTITION p20260501 VALUES LESS THAN (TO_DAYS('2026-05-02')),
PARTITION p20260502 VALUES LESS THAN (TO_DAYS('2026-05-03')),
...
);
행 지향 DB 의 정석으로 짰다. PK 는 (host, metric_name, ts) 로 가장 흔한 쿼리 패턴 ("특정 host 의 특정 metric 시계열") 에 맞췄다. 추가로 region 진입 쿼리를 위한 보조 인덱스 1개, metric 단독 진입을 위한 인덱스 1개를 만들어줬다. 시간 기반 운영 (TTL, partition pruning) 을 위해 일 단위 RANGE 파티션을 30개 정의해뒀다.
ClickHouse 스키마
CREATE TABLE metrics (
ts DateTime CODEC(DoubleDelta, ZSTD(3)),
host LowCardinality(String),
metric_name LowCardinality(String),
region LowCardinality(String),
env LowCardinality(String),
value Float64 CODEC(Gorilla, ZSTD(3)),
tags Map(LowCardinality(String), String)
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(ts)
ORDER BY (metric_name, host, ts)
SETTINGS index_granularity = 8192;
같은 데이터인데 모양이 꽤 다르다. 핵심 차이를 정리하면 다음과 같다.
| 항목 | MySQL | ClickHouse |
|---|---|---|
| Engine | InnoDB (B+tree) | MergeTree (LSM + 컬럼형) |
| 정렬 결정 | PK 가 정렬 결정 | ORDER BY 별도 절 |
| PK 의미 | unique 제약 + 정확한 인덱스 | unique 강제 X, 희소 인덱스 진입점 |
| 보조 인덱스 | B-tree 여러 개 | Projection (다른 정렬로 복제) |
| 압축 | 테이블 단위 옵션 | 컬럼별 코덱 체인 |
| string 효율 | VARCHAR | LowCardinality(String) |
| TTL | 별도 운영 (cron / 파티션 drop) | TTL ts + INTERVAL 30 DAY 한 줄 |

MySQL 인덱스의 일반 원칙은 "카디널리티 높은 컬럼을 앞에 두라" 인데, ClickHouse ORDER BY 는 정반대로 카디널리티 낮은 컬럼을 앞에 둬야 한다. MySQL 의 인덱스 설계 감각으로 ClickHouse 정렬 키를 짜면 오히려 더 느린 결과가 나올 수도 있다는 뜻이다.
왜 정반대인지를 정리해보면 다음과 같다.
- MySQL B-tree 인덱스: 1억 행 중 정확한 1개를 빠르게 찾는 것이 목적. 카디널리티가 높을수록 selectivity 가 좋아져 후보가 빠르게 좁혀진다.
- ClickHouse ORDER BY: 같은 값끼리 디스크에 인접하게 모아두는 것이 목적. 카디널리티가 낮을수록 큰 덩어리가 만들어져 압축률·Zone Map 효과가 같이 좋아진다.
1편에서 다뤘던 "조밀 인덱스 vs 희소 인덱스" 차이의 자연스러운 연장선으로 보인다. 조밀 인덱스 (B-tree) 는 점 위치를 찾으니 selectivity 우선, 희소 인덱스 (ClickHouse PK) 는 블록 시작점을 찾으니 같은 값이 모여 있어야 효율이 높다.
컬럼별 코덱
ts 컬럼에 DoubleDelta, value 컬럼에 Gorilla 코덱을 지정했다. 1편에서 다뤘던 "같은 타입이 모여 있어 압축이 잘된다" 이론의 가장 구체적인 도구다.
- DoubleDelta: 단조 증가하는 timestamp 에 특화. 1차 차분이 일정 (10초 간격) → 2차 차분이 거의 0 → 0 이 연속되니 압축률이 극단적으로 좋아진다.
- Gorilla: Facebook 이 시계열 float 용으로 만든 알고리즘. 연속된 값을 XOR 한 결과를 저장한다. 천천히 변하는 메트릭에 특화돼 있다.
뒤에 ZSTD(3) 도 같이 체인으로 연결한다. 컬럼 특성에 맞는 코덱이 1차 인코딩, ZSTD 가 범용 압축. 한 컬럼에 두 단계가 동시에 적용되는 셈이다.
실험 셋업
Docker Compose 로 두 DB 를 동일한 자원 제한 (CPU 4코어, RAM 8GB) 하에서 같이 띄웠다. MySQL innodb_buffer_pool_size=2G, ClickHouse mark/uncompressed cache 각각 2GB 로 캐시 비율도 맞췄다.
측정 프로토콜은 1편에서 정리했던 변인 통제 원칙대로 진행했다.
- 콜드: 컨테이너 stop →
sudo purge(OS page cache drop) → 컨테이너 start → 쿼리 1회 실행 - 웜: warm-up 1회 (버려짐) + 5회 측정 → 평균 + 표준편차
쿼리는 1편 시나리오들을 토대로 7가지를 정했다. 각 쿼리가 1편 이론의 어느 주장을 검증하는지 미리 매핑해뒀다.
| Q | 시나리오 | 예상 결과와 1편 이론 |
|---|---|---|
| Q1 | 대시보드에서 task-01 호스트의 지난 1시간 cpu 사용률 추이 |
정렬 키 (host, metric, ts) 와 정확히 매치되는 쿼리라 양쪽 다 인덱스만으로 좁힐 수 있어, 1편의 "정렬 매치 시 동등" 대로 비슷하게 빠를 것 |
| Q2 | 7일간 us-east region 전체의 cpu 사용률 분 단위 추이 | region 이 ClickHouse 정렬 키의 leading 이 아니라 추가 필터링이 필요한 반면, MySQL 은 idx_region_metric_ts 가 정확히 맞아 — 1편의 "non-leading 진입" 약점이 드러나야 할 자리 |
| Q3 | 어제 하루 동안 cpu 사용률이 80% 를 넘긴 호스트 목록 (알림 회고) | value 한 컬럼만 보면 되고 ts 범위는 Zone Map 으로 좁힐 수 있어, 1편의 "필요 컬럼만 읽기" 가 잘 보여야 할 위치 |
| Q4 | 지난 7일치 cpu 사용률을 분 단위로 다운샘플링 (장기 그래프) | 7일치 cpu = 약 3천만 행 집계인데, ClickHouse 는 value + ts 두 컬럼만 읽고 벡터화 집계, MySQL 은 모든 컬럼을 페이지째 읽어야 함 — 1편 이론대로면 가장 차이가 큰 자리 |
| Q5 | 지난 1시간 평균 cpu 사용률 상위 10개 호스트 | host 카디널리티가 50으로 작고 1시간 좁은 범위라, 인덱스 매치만으로 양쪽 비슷할 것으로 예상 |
| Q6 | 수집 daemon 이 10초마다 1건씩 INSERT 하는 패턴 (1,000회 반복) | ClickHouse LSM 은 INSERT 마다 작은 part 가 생기고 머지가 필요해서, 1편의 "단건 쓰기 약점" 대로 MySQL 이 더 빠를 것 |
| Q7 | 장애 복구 후 누락된 1시간치 (27만 행) 데이터를 한 번에 적재 | 벌크 적재는 ClickHouse LSM 의 sweet spot. 1편의 "모아서 한 번에" 패턴이 그대로 작동해 ClickHouse 가 훨씬 빠를 것 |
측정 결과

전체 결과를 정리하면 다음과 같다 (warm avg 기준, ms).
| 쿼리 | MySQL | ClickHouse | 결과 |
|---|---|---|---|
| Q1 단일 host 시계열 (1h) | 68 | 76 | 비슷 |
| Q2 region 집계 (7d) | 961 | 84 | CH 11.4x |
| Q3 알림 스캔 (1d) | 378 | 79 | CH 4.8x |
| Q4 다운샘플링 (7d) | 8,029 | 97 | CH 82.8x |
| Q5 top-N (1h) | 79 | 86 | 비슷 |
| Q6 단건 INSERT × 1,000 | 570 | 880 | MySQL 1.5x |
| Q7 벌크 백필 (270K) | 2,053 | 285 | CH 7.2x |
큰 그림은 1편 결론이 거의 그대로 보인다. 다만 쿼리별로 들여다보면 디테일이 적지 않다.
Q4 - 차이가 가장 큰 다운샘플링
가장 차이가 컸던 결과. "7일치 cpu_user 의 분 단위 평균" 을 구하는 쿼리다. 1편에서 "컬럼형이 가장 빛난다" 고 했던 대규모 집계 + 필요 컬럼만 읽기 패턴에 그대로 부합한다.
MySQL 8초, ClickHouse 97ms. 약 82배 차이.
MySQL EXPLAIN 결과를 보니 흥미롭게도 풀스캔을 채택했다. 인덱스 후보가 3개 있었는데 (PRIMARY, idx_region_metric_ts, idx_metric_ts) 옵티마이저가 셋 다 무시했다. 약 4,700만 행을 스캔하면서 3GB 데이터를 읽었다 (access_type: ALL, rows_examined_per_scan: 47228763, data_read_per_join: 3G). Partition pruning 으로 7일치 파티션 8개로 범위를 좁힌 게 그나마 다행이었다.
ClickHouse 는 같은 의미의 쿼리에서 ts 컬럼과 value 컬럼 두 개만 읽고 약 42MB 만 스캔했다. metric_name 필터는 정렬 키 prefix 라 sparse index 로 좁힐 수 있었고, GROUP BY + AVG 는 벡터화된 컬럼 연산으로 처리.
Q2, Q3 - 데이터 양이 작으면 차이가 안 보인다
Q2 를 처음엔 "1시간 us-east region cpu 평균" 으로 설계했었다. 측정해보니 MySQL 74ms, ClickHouse 78ms. 1편 이론대로면 ClickHouse 가 살짝 우세해야 할 자리인데 결과가 거의 비슷하게 나와서 의아했다.
원인은 단순했다. 데이터 범위가 너무 작아서 양쪽 다 인덱스로 빠르게 좁힐 수 있었기 때문이다. 1편에서 다뤘던 컬럼형의 압축·Zone Map 이점이 발휘되려면 어느 정도 데이터 양이 있어야 한다는 점을 거꾸로 확인한 셈이다.
범위를 1시간에서 7일로 늘려 다시 측정해봤다. MySQL 961ms, ClickHouse 84ms. 11배 차이로 벌어졌다.
Q3 도 비슷한 패턴이었다. 원래 "지난 5분간 cpu > 80% 였던 host" 였는데, 5분 데이터가 너무 작아서 (15,000 행 정도) MySQL 이 오히려 더 빠른 결과가 나왔다. ClickHouse 의 한 블록 단위 (8192 행) 가 데이터 전체 크기에 가까운 상황이라 컬럼형의 효율이 발휘되지 않은 것 같다.
1일로 늘려보니 (432,000 행) MySQL 378ms, ClickHouse 79ms 로 5배 차이가 났다.
이 두 케이스에서 정리한 점은 이렇다. 1편의 "컬럼형은 빠르다" 는 데이터 양이 충분히 클 때 성립한다. 작은 범위 쿼리는 두 DB 모두 인덱스로 처리해버려서 컬럼형의 이점이 잘 드러나지 않는다.
Q1, Q5 - 작은 쿼리에선 양쪽이 비슷하다
Q1 (특정 host 시계열 1시간) 과 Q5 (top-N 1시간) 는 양쪽이 거의 같은 시간이 나왔다. 결과가 작아서 (~360 ~ 18,000 행) 양쪽 모두 인덱스 매치만으로 처리할 수 있었기 때문이다.
이 결과는 1편 결론을 부정하는 게 아니다. PK 매치되는 작은 쿼리는 row DB 도 충분히 빠르다. 1편에서 "행 지향도 정렬·인덱스 매치는 빠르다" 고 정리했던 부분이 그대로 보인다.
Q6 - Column DB 의 의도된 약점
단건 INSERT 1,000 회를 반복한 결과. MySQL 570ms, ClickHouse 880ms. MySQL 이 1.5배 빠르다.
이 결과는 의도한 것이다. 1편에서 다룬 그대로다. LSM 기반인 ClickHouse 는 매 INSERT 마다 작은 part 가 만들어지고 백그라운드 머지가 필요해서, 단건 OLTP 스러운 쓰기에는 약하다. MergeTree 의 본질이 "모아서 한 번에" 라 단건 쓰기는 비싸다.
이걸 1만번, 10만번 반복하면 ClickHouse 에 Too many parts 에러가 나기 시작한다. 메트릭 수집 시스템이 ClickHouse 를 쓸 때 보통 배치 윈도우 (수초~수십초) 단위의 벌크 적재로 전환하는 이유다.
Q7 - 벌크는 정반대
같은 INSERT 라도 27만 행을 한 번에 넣으면 결과가 뒤집힌다.
MySQL 2,053ms, ClickHouse 285ms. ClickHouse 가 7배 빠르다. 1편의 "벌크는 강하다" 가 그대로 나타난 결과다.
MySQL 은 B+tree 인덱스 3개를 갱신하느라 시간을 쓰고 (벌크 트릭으로 unique_checks=0, autocommit=0 옵션을 켜뒀는데도), ClickHouse 는 압축과 정렬을 일괄 처리하면서 LSM 의 sweet spot 에서 동작한다.
디스크 사용량 - 22배 차이

쿼리 속도보다 더 직관적으로 보이는 차이가 디스크 사용량이다.
| 데이터 | 인덱스 | 합계 | |
|---|---|---|---|
| MySQL | 15.4 GB | 13.8 GB | 29.2 GB |
| ClickHouse | 1.33 GB (압축) | 0 (sparse) | 1.33 GB |
22배 차이. 같은 1억 9,400만 행을 저장한 결과다.
MySQL 쪽은 데이터 못지않게 인덱스 자체가 무겁다 (PK + 보조 인덱스 2개). 1편에서 정리한 "행 지향은 조밀 인덱스라 인덱스 비용이 크다" 가 그대로 보이는 부분이다. ClickHouse 는 희소 인덱스라 사실상 메모리에만 올라가고 디스크엔 거의 없다.
ClickHouse 의 컬럼별 압축률을 들여다보면 차이가 더 인상적이다.
| 컬럼 | 압축률 | 코덱 / 옵션 |
|---|---|---|
ts |
700x | DoubleDelta + ZSTD(3) |
tags |
224x | (빈 Map) |
metric_name |
211x | LowCardinality |
env |
194x | LowCardinality |
host |
167x | LowCardinality |
region |
166x | LowCardinality |
value |
1.1x | Gorilla + ZSTD(3) |
ts 가 700배. 10초 간격 timestamp 의 차분 (10 으로 일정) 의 또 차분 (0) 으로 만들어주니 거의 사라지는 수준이다. 1편에서 다뤘던 압축 이론의 가장 시각적인 예시라고 할 수 있다.
string 컬럼들도 166~211배 압축됐다. LowCardinality(String) 가 내부적으로 딕셔너리를 만들어 작은 정수 ID 로 저장하는데, 같은 값 (region=us-east 같은) 이 반복되는 메트릭 데이터에 정확히 들어맞는 방식이다.
그런데 value 컬럼은 압축률 1.1배
value 컬럼 결과는 의외였다. Gorilla 가 제 역할을 못 했다.
원인을 파보니 합성 데이터의 분포 문제였던 것 같다. cpu_user 같은 값을 25 + sin 파동 + 정규분포 노이즈 + 가끔 spike 로 생성했는데, 노이즈 때문에 매번 다른 부동소수점 값 이 나온다. Gorilla 는 "이전 값과 비슷한 값" 의 패턴을 XOR 로 압축하는 알고리즘이라, 매번 값이 다르면 압축 여지가 거의 없다.
실제 메트릭 시스템은 보통 더 step-wise 한 값을 받는다 (반올림된 정수, 0.1 단위 백분율 등). 그런 데이터에선 Gorilla 가 훨씬 잘 압축한다고 알려져 있다.
1편에서 정리한 "유사한 값이 연속이면 압축 0에 수렴" 이론 자체는 맞지만, 실측 결과는 데이터 분포에 강하게 의존한다는 점을 같이 보여주는 셈이다. 운영 데이터로 다시 측정하면 value 압축률도 훨씬 좋게 나올 가능성이 크다. 다음 측정에 참고해야 할 변수로 두려 한다.
Projection 추가 측정
1편에서 다룬 컬럼형 인덱스 전략 중 하나가 Projection 이었다. "정렬 키가 아닌 컬럼으로 진입해야 하는 쿼리를 위해 같은 데이터를 다른 정렬로 한 벌 더 저장" 하는 트릭이다.
Q2 (region 진입 7일 집계) 에 projection 을 추가하고 효과를 측정해봤다.
ALTER TABLE metrics ADD PROJECTION p_region (
SELECT * ORDER BY (region, metric_name, ts)
);
ALTER TABLE metrics MATERIALIZE PROJECTION p_region;
200M 행에 대한 MATERIALIZE 가 34초 만에 끝났다. 디스크는 1.33 GB 에서 2.34 GB 로 75% 증가 (projection 이 사실상 데이터 한 벌 더 저장하기 때문이다).
Q2 를 다시 측정한 결과는 다음과 같다.
| warm avg | |
|---|---|
| no projection | 88ms |
| with projection | 84ms |
1.1배 차이. 거의 안 변했다. "정말 동작한 것 맞나" 싶을 정도였다.

system.query_log 를 들여다보니 실제 동작은 달랐다.
| rows | bytes | |
|---|---|---|
| no projection | 3,473,408 | 24.10 MiB |
| with projection | 638,976 (5.4x ↓) | 8.53 MiB (2.8x ↓) |
Projection 은 1편 이론대로 정확히 동작했다. 스캔 행수가 5.4배, 바이트가 2.8배 줄었다. ClickHouse 서버 쪽 실행 시간도 10ms → 5ms 로 절반이 됐다.
그런데 wall-clock 측정은 88ms → 84ms 로 거의 그대로였다. 이유는 단순했는데, docker exec 오버헤드 (약 70ms) 가 측정값의 대부분을 차지해서 서버 시간 5ms 차이가 그 안에 묻혔던 것이다.
이 부분은 측정 방법론의 한계로 봐야 할 것 같다. 작은 쿼리 (서버 처리 50ms 이하) 의 컬럼형 미세 최적화 효과를 보려면 docker exec wall-clock 보다 system.query_log 나 EXPLAIN ANALYZE 를 봐야 정확하다. Q4 처럼 서버 처리 자체가 수 초 단위인 쿼리는 wall-clock 만으로도 충분히 보이지만.
1편 이론과 실측 정리
| 1편 이론 | 검증 결과 |
|---|---|
| 필요 컬럼만 읽기 | ✅ Q4 82x, Q2 11x |
| 압축 효율 (string, timestamp) | ✅ ts 700x, string 167~211x |
| 압축 효율 (numeric) | ⚠️ value 1.1x (데이터 분포에 의존) |
| Zone Map / 블록 스킵 | ✅ 8/31 partition, 6336/23793 granule |
| 희소 인덱스 + 정렬 | ✅ Q1, Q5 에서 동등 성능 |
| Projection 효과 | ✅ 스캔 5.4x ↓ (wall-clock 엔 1.1x로만 보임) |
| 단건 쓰기 약점 | ✅ Q6 MySQL 1.5x 우세 |
| 벌크는 강하다 | ✅ Q7 ClickHouse 7x 우세 |
이론에서 살짝 벗어난 부분 (value 압축) 도 이론 자체의 문제라기보다 데이터 분포라는 추가 변수의 영향으로 보인다. 큰 그림은 1편 결론이 거의 그대로 입증됐다고 봐도 될 것 같다.
다만 측정 과정에서 추가로 얻은 인사이트도 몇 가지 있었다.
- 데이터 양이 충분히 커야 컬럼형의 이점이 보인다 (Q2 1시간 → 7일 변경 후 차이 11배 등장)
- MySQL 옵티마이저는 큰 집계 쿼리에서 인덱스를 무시하고 풀스캔을 선택할 수도 있다 (Q4 EXPLAIN 결과)
- 마이크로벤치마크의 wall-clock 측정은 docker exec 오버헤드에 가려질 수 있다. 작은 쿼리는 EXPLAIN / query_log 를 같이 봐야 정확하다
마무리, 그리고 3편
여기까지 보면 컬럼형 DB 가 메트릭 모니터링 시나리오에서 거의 모든 측면에서 좋아 보인다. 디스크 22배 절약, 분석 쿼리 80배 빠름, 벌크 적재 7배 빠름.
다만 이게 정답인지는 좀 더 고민해야 할 것 같다. 단건 쓰기 약점 (Q6) 만 보더라도 OLTP 워크로드에는 안 맞고, 같은 메트릭 시스템이라도 회사마다 다른 솔루션을 쓰고 있다. Netflix Atlas 는 Cassandra 위에 만들어졌고, Prometheus 는 자체 TSDB 를 쓰고, 일부는 InfluxDB / TimescaleDB 같은 시계열 전용 DB 를 쓴다.
3편에선 "같은 메트릭 시스템 문제를 ClickHouse 가 아닌 다른 방식으로 풀면 어떻게 되는가" 를 비교해보려 한다. 후보로 떠올린 것들은 다음과 같다.
- MySQL + 사전 집계 (Materialized View) — row DB 안에서 해결 시도
- Cassandra — 분산 wide-column NoSQL 의 관점
- TimescaleDB / InfluxDB — 시계열 전용 DB
- Apache Druid — 또 다른 컬럼형 OLAP
비교축이 "단일 노드 컬럼형 vs 다른 모든 것" 으로 나뉘면 ClickHouse 가 갖는 trade-off 가 좀 더 선명해질 것 같다. ClickHouse 가 만능인지 특정 상황에서만 답인지를 다음 편에서 직접 측정해보려고 한다.
부록 - 재현 방법
전체 코드와 측정 결과는 github.com/gmelon/blog-post-and-code 의 columnar-db-bench 디렉토리에 올려뒀다.
git clone https://github.com/gmelon/blog-post-and-code.git
cd blog-post-and-code/columnar-db-bench
docker compose up -d
python3 generate.py # ~10분, 1.94억 행 CSV 생성
./scripts/init_mysql.sh
./scripts/init_clickhouse.sh
./scripts/load_mysql.sh # ~1시간
./scripts/load_clickhouse.sh # ~10분
./scripts/disk_usage.sh
sudo -v
./scripts/benchmark.sh # ~30~60분
./scripts/projection_demo.sh # ~15분
python3 scripts/analyze.py results/all.csv
데이터 생성은 random.seed(42) 로 고정해뒀으므로 누구나 같은 결과를 얻을 수 있다. 측정 환경 차이가 있으면 절대값은 달라지겠지만 두 DB 간 상대 차이는 비슷하게 나올 것이다.
'개발 공부 > DB' 카테고리의 다른 글
| [컬럼형 DB 파헤치기] 1편 - Row DB와 뭐가 다른가 (0) | 2026.05.24 |
|---|---|
| 왜 서로 다른 값을 INSERT 했는데 데드락이 걸릴까? (0) | 2026.02.02 |