TimescaleDB: PostgreSQL 위에서 시계열 처리
PostgreSQL을 버리지 않는 선택
새로운 시계열 데이터베이스를 도입할 때 가장 큰 장벽은 기존 PostgreSQL 생태계와의 단절이다. JOIN, 외래 키, 복잡한 SQL, ORM, BI 도구, psycopg2/libpq 드라이버... 이 모든 것을 포기하고 새 도구의 쿼리 언어와 운영 방식을 익혀야 한다.
TimescaleDB는 이 문제를 다르게 접근한다. PostgreSQL을 교체하는 대신 PostgreSQL 확장(extension)으로 설치해, 기존 SQL 인터페이스를 그대로 유지하면서 시계열 워크로드 성능을 크게 높인다.
-- 일반 PostgreSQL 테이블처럼 만들고...
CREATE TABLE metrics (
time TIMESTAMPTZ NOT NULL,
host TEXT,
cpu_percent DOUBLE PRECISION
);
-- 한 줄로 하이퍼테이블로 변환
SELECT create_hypertable('metrics', by_range('time'));이후 INSERT, SELECT, JOIN, GROUP BY는 평범한 PostgreSQL SQL 그대로다. 쿼리 플래너가 내부적으로 파티션을 인식하고 최적화할 뿐이다.
핵심 개념: 하이퍼테이블과 청크
하이퍼테이블(Hypertable)은 TimescaleDB가 제공하는 가상 테이블이다. 외부에서 보면 단일 테이블처럼 보이지만, 내부적으로 시간 범위에 따라 여러 청크(Chunk)로 자동 분할된다.
각 청크는 실제 PostgreSQL 테이블이다. PostgreSQL의 파티션 테이블과 유사하지만, TimescaleDB가 파티션 생성·삭제·압축 등을 자동으로 관리한다는 점이 다르다.
청크 크기 설정 기준: 메모리의 25% 정도가 하나의 청크에 들어오는 크기가 권장값이다. 청크 크기가 너무 작으면 Catalog 메타데이터가 폭발하고, 너무 크면 청크 압축·삭제 작업이 오래 걸린다.
Hypercore: 행-열 하이브리드 스토리지
TimescaleDB 2.18(2025년 12월)에서 정식 출시된 Hypercore는 하나의 하이퍼테이블이 로우스토어(Rowstore)와 컬럼스토어(Columnstore)를 동시에 유지하는 혼합 스토리지 엔진이다.
• 표준 PostgreSQL 힙(heap) 테이블
• INSERT / UPDATE / DELETE 완전 지원
• 인덱스도 일반 B-Tree 그대로
• 쓰기 성능 최우선
• 컬럼 단위 저장 → 집계 쿼리 I/O 대폭 감소
• 압축률 최대 98% (zstd + 특화 인코딩)
• 변환 후에도 일반 SELECT로 투명하게 조회
• 수정은 비동기 재압축으로 처리
add_columnstore_policy('metrics', after => INTERVAL '7 days') —
7일 지난 청크는 자동으로 컬럼스토어로 전환. 애플리케이션 코드 변경 없음.
SELECT avg(cpu_percent) FROM metrics WHERE time > now() - INTERVAL '30d'→ 플래너가 자동으로 로우스토어와 컬럼스토어를 결합해 최적 계획 수립. 사용자는 스토리지 형태를 신경 쓸 필요 없음.
압축 인코딩 방식:
| 데이터 타입 | 인코딩 방법 |
|---|---|
| 타임스탬프, 정수 | Delta + Delta-of-Delta + Simple-8b |
| 부동소수점 | XOR 기반(Gorilla 변형) |
| 반복 값 많은 컬럼 | Run-Length Encoding (RLE) |
| 문자열/고카디널리티 | Dictionary 압축 |
| 일반 | zstd 블록 압축 |
연속 집계(Continuous Aggregates)
시계열 데이터의 가장 일반적인 쿼리 패턴은 "지난 1시간의 평균 CPU를 1분 단위로"처럼 시간 버킷 집계다. 원본 테이블에 매번 쿼리하면 수십억 행을 스캔해야 한다. Continuous Aggregate는 이 집계 결과를 물질화(materialization)하고 증분 갱신하는 기능이다.
-- 1분 단위 CPU 평균을 사전 집계
CREATE MATERIALIZED VIEW metrics_1min
WITH (timescaledb.continuous) AS
SELECT
time_bucket('1 minute', time) AS bucket,
host,
avg(cpu_percent) AS avg_cpu,
max(cpu_percent) AS max_cpu
FROM metrics
GROUP BY bucket, host;
-- 자동 갱신 정책: 최근 1시간 데이터를 1분마다 갱신
SELECT add_continuous_aggregate_policy('metrics_1min',
start_offset => INTERVAL '2 hours',
end_offset => INTERVAL '1 minute',
schedule_interval => INTERVAL '1 minute');갱신 정책의 핵심은 변경된 시간 버킷만 재계산한다는 점이다. 새 데이터가 2026-07-12 14:35에 들어오면 14:35 버킷만 다시 집계하고, 나머지는 그대로 유지한다.
계층적 연속 집계: Continuous Aggregate 위에 또 다른 Continuous Aggregate를 쌓아 1분 → 1시간 → 1일로 롤업 체인을 구성할 수 있다. 각 레벨은 이전 레벨의 결과만 읽어 갱신하므로 원본 테이블 접근을 최소화한다.
보존 정책과 데이터 계층화
-- 3개월 지난 청크 자동 삭제
SELECT add_retention_policy('metrics', INTERVAL '3 months');
-- 30일 지난 데이터를 S3(Tiered Storage)로 이동
SELECT add_tiering_policy('metrics', INTERVAL '30 days');Timescale의 계층형 스토리지(Tiered Storage)는 오래된 청크를 S3 호환 오브젝트 스토리지로 이동하면서도 SQL SELECT로 투명하게 조회한다. 자주 쓰는 최근 데이터는 로컬 SSD에, 장기 보존 데이터는 저비용 오브젝트 스토리지에 유지하는 패턴이다.
공간 분할(Space Partitioning)
시간 파티셔닝만으로는 단일 노드의 쓰기 병목을 해결하기 어렵다. 공간 분할은 시간 차원 외에 추가 컬럼(예: host)으로도 청크를 나눠 쓰기를 여러 청크에 분산한다.
SELECT create_hypertable('metrics',
by_range('time'),
by_hash('host', 4) -- host 값을 해시해서 4개 공간 파티션
);공간 파티션을 늘리면 동시 쓰기 처리량이 높아지지만, 쿼리가 특정 host를 지정하지 않으면 모든 공간 파티션을 읽어야 해서 쿼리 성능이 떨어질 수 있다.
TimescaleDB의 PostgreSQL 활용 전략
TimescaleDB가 PostgreSQL을 사용한다는 것의 실질적인 장점을 세 가지로 정리한다.
- 시계열 테이블 ↔ 메타 테이블 JOIN
- 외래 키, 유니크 제약
- 윈도우 함수, CTEs
- 트랜잭션 ACID 보장
- psql, pgAdmin, DBeaver
- pg_dump / pg_restore
- SQLAlchemy, GORM, Diesel
- Grafana PostgreSQL 데이터소스
- PostGIS (지리 데이터)
- pg_stat_statements
- pgvector (임베딩)
- Citus (분산 쿼리)
JOIN의 실질적 가치: IoT 센서 메트릭 테이블과 sensors 메타 테이블(위치, 모델, 담당자)을 JOIN해 "XX 지역 센서의 어제 평균 온도"를 단일 쿼리로 구할 수 있다. InfluxDB 같은 순수 TSDB에서는 이 작업에 애플리케이션 레벨 조인이나 별도 데이터 파이프라인이 필요하다.
성능 특성과 한계
강점:
- Hypercore 압축 후 집계 쿼리: 10~100x 속도 향상
- Continuous Aggregate 조회: 미리 집계된 결과 반환, 밀리초 단위
- 쓰기 성능: PostgreSQL 단독 대비 5~10x (청크별 INSERT 병렬화)
한계:
- 수평 확장 제한: 단일 PostgreSQL 인스턴스 기반. 쓰기 처리량의 천장이 존재한다. (Citus 확장 통합으로 부분 해결 가능하나 복잡도 증가)
- 고카디널리티 시리즈 인덱스: InfluxDB IOx와 달리 PostgreSQL의 B-Tree 인덱스를 사용하므로, 카디널리티가 수천만 이상이 되면 인덱스 관리 비용이 올라간다.
- WAL 부하: Hypercore의 컬럼스토어 변환 과정도 WAL을 통해 기록되므로, 압축 정책이 공격적이면 WAL 생성량이 늘어 복제 지연이 발생할 수 있다.
언제 TimescaleDB를 선택하는가
| 상황 | 추천 |
|---|---|
| 시계열 + 관계형 데이터를 함께 다루고 JOIN이 필수 | TimescaleDB |
| 기존 PostgreSQL 인프라·팀 역량 유지 | TimescaleDB |
| 단일 노드 또는 소규모 클러스터로 충분 | TimescaleDB |
| 수억 시리즈, 초당 수백만 쓰기 요구 | InfluxDB IOx / VictoriaMetrics |
| Prometheus 메트릭 장기 저장만 필요 | VictoriaMetrics / Thanos |
| SQL 없이 운영·개발 비용 최소화 | InfluxDB Cloud Serverless |
핵심 판단 기준: 데이터 파이프라인에서 시계열 데이터가 관계형 데이터와 함께 쓰여야 한다면 TimescaleDB가 자연스러운 선택이다. 순수 메트릭 저장과 대규모 수평 확장이 목적이라면 InfluxDB나 VictoriaMetrics가 더 적합하다.
References
- TimescaleDB 공식 문서 — Hypertables, https://docs.timescale.com/use-timescale/latest/hypertables/
- TimescaleDB 공식 문서 — Continuous Aggregates, https://docs.timescale.com/use-timescale/latest/continuous-aggregates/
- TigerData 문서 — Hypercore 이해하기, https://www.tigerdata.com/docs/learn/columnar-storage/understand-hypercore
- jusdb.com — TimescaleDB Hypertables, Continuous Aggregates & Compression (2026 Production Guide), https://www.jusdb.com/blog/timescaledb-hypertables-continuous-aggregates-guide
- roszigit.com — TimescaleDB Compression: Hypercore and Columnar Storage with up to 98% Ratio in PostgreSQL, https://roszigit.com/en/blog/timescaledb-compression-hypercore/
- TimescaleDB Architecture Whitepaper (TigerData), https://assets.timescale.com/docs/downloads/tigerdata-whitepaper.pdf
- GitHub — timescale/timescaledb, https://github.com/timescale/timescaledb
- Aliaksandr Valialkin — High-cardinality TSDB benchmarks: VictoriaMetrics vs TimescaleDB vs InfluxDB, https://valyala.medium.com/high-cardinality-tsdb-benchmarks-victoriametrics-vs-timescaledb-vs-influxdb-13e6ee64dd6b
- modern-datatools.com — TimescaleDB Review (2026), https://www.modern-datatools.com/tools/timescaledb