저장 효율
저장 효율 (Storage efficiency)
ClickHouse에서 시계열 데이터의 저장 공간을 타입 최적화와 전문화된 코덱으로 절약하는 방법을 살펴봐요.
출처: 문서
본문
Wikipedia 통계 데이터셋을 조회하는 방법을 탐구한 뒤, ClickHouse에서 그 저장 효율을 최적화하는 데 초점을 맞춰 볼게요. 이 섹션은 쿼리 성능을 유지하면서 저장 요구 사항을 줄이는 실용적인 기법을 보여줘요.
타입 최적화
저장 효율을 최적화하는 일반적인 접근 방식은 최적의 데이터 타입을 사용하는 거예요. project와 subproject 컬럼을 살펴볼게요. 이 컬럼들은 String 타입이지만 고유 값 수가 상대적으로 적어요:
SELECT
uniq(project),
uniq(subproject)
FROM wikistat;
┌─uniq(project)─┬─uniq(subproject)─┐
│ 1332 │ 130 │
└───────────────┴──────────────────┘
이는 사전 기반 인코딩을 사용하는 LowCardinality() 데이터 타입을 사용할 수 있다는 뜻이에요. 이는 ClickHouse가 원래 문자열 값 대신 내부 값 ID를 저장하게 해서 많은 공간을 절약해요:
ALTER TABLE wikistat
MODIFY COLUMN `project` LowCardinality(String),
MODIFY COLUMN `subproject` LowCardinality(String)
hits 컬럼에는 8바이트를 차지하는 UInt64 타입도 사용했지만, 최대 값이 상대적으로 작아요:
SELECT max(hits)
FROM wikistat;
┌─max(hits)─┐
│ 449017 │
└───────────┘
이 값을 감안하면 4바이트만 차지하고 최대 약 40억까지 저장할 수 있는 UInt32를 사용할 수 있어요:
ALTER TABLE wikistat
MODIFY COLUMN `hits` UInt32;
이러면 이 컬럼의 메모리 크기가 최소 2배 줄어들 거예요. 압축 덕분에 디스크의 크기는 변하지 않는다는 점에 유의하세요. 하지만 너무 작지 않은 데이터 타입을 선택하도록 주의하세요!
전문화된 코덱
시계열처럼 순차적인 데이터를 다룰 때 특수 코덱을 사용해 저장 효율을 더 개선할 수 있어요. 일반적인 아이디어는 절대 값 자체 대신 값 사이의 변화를 저장하는 것으로, 천천히 변하는 데이터를 다룰 때 필요한 공간이 훨씬 적어져요:
ALTER TABLE wikistat
MODIFY COLUMN `time` CODEC(Delta, ZSTD);
time 컬럼에 Delta 코덱을 사용했는데, 이는 시계열 데이터에 잘 맞아요. 올바른 정렬 키도 디스크 공간을 절약할 수 있어요. 보통 path로 필터링하기 때문에 정렬 키에 path를 추가할 거예요. 이는 테이블 재생성이 필요해요. 아래에서 초기 테이블과 최적화된 테이블의 CREATE 명령을 볼 수 있어요:
CREATE TABLE wikistat
(
`time` DateTime,
`project` String,
`subproject` String,
`path` String,
`hits` UInt64
)
ENGINE = MergeTree
ORDER BY (time);
CREATE TABLE optimized_wikistat
(
`time` DateTime CODEC(Delta(4), ZSTD(1)),
`project` LowCardinality(String),
`subproject` LowCardinality(String),
`path` String,
`hits` UInt32
)
ENGINE = MergeTree
ORDER BY (path, time);
각 테이블의 데이터가 차지하는 공간을 살펴볼게요:
SELECT
table,
formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
formatReadableSize(sum(data_compressed_bytes)) AS compressed,
count() AS parts
FROM system.parts
WHERE table LIKE '%wikistat%'
GROUP BY ALL;
┌─table──────────────┬─uncompressed─┬─compressed─┬─parts─┐
│ wikistat │ 35.28 GiB │ 12.03 GiB │ 1 │
│ optimized_wikistat │ 30.31 GiB │ 2.84 GiB │ 1 │
└────────────────────┴──────────────┴────────────┴───────┘
최적화된 테이블은 압축 형태에서 4배 이상 적은 공간을 차지해요.