개요

시계열 데이터베이스(Time-Series Database)는 시간에 따라 변화하는 데이터를 효율적으로 저장하고 분석하기 위한 전문 데이터베이스입니다. IoT 센서 데이터, 서버 모니터링 메트릭, 금융 거래 데이터, 사용자 행동 로그 등에서 필수적으로 사용됩니다. 이 글에서는 TimescaleDB, InfluxDB, QuestDB 세 가지 주요 시계열 DB를 아키텍처, 성능, 사용성 관점에서 비교합니다.

핵심 개념

TimescaleDB: PostgreSQL 확장으로 구현된 시계열 DB입니다. PostgreSQL의 모든 기능(JOIN, 서브쿼리, 인덱스, 확장)을 그대로 사용할 수 있으면서, 하이퍼테이블(Hypertable)이라는 시간 기반 자동 파티셔닝으로 시계열 쿼리 성능을 최적화합니다. 2024년부터 컬럼 압축이 크게 개선되어 저장 효율이 최대 98% 향상되었습니다.

InfluxDB: 시계열 데이터에 특화된 전용 데이터베이스입니다. InfluxDB 3.0(2024)에서 Apache Arrow 기반으로 완전히 재작성되어, Parquet 형식의 컬럼 스토리지를 사용합니다. Flux 언어 대신 SQL과 InfluxQL을 지원하며, 성능이 대폭 향상되었습니다.

QuestDB: Java로 작성된 고성능 시계열 DB로, PostgreSQL 와이어 프로토콜과 InfluxDB 라인 프로토콜을 모두 지원합니다. SIMD 명령어를 적극 활용하여 집계 쿼리에서 매우 빠른 성능을 보여줍니다. SQL 확장으로 SAMPLE BY, LATEST ON 같은 시계열 전용 문법을 제공합니다.

실전 예제

각 DB에서 동일한 시계열 작업을 수행하는 비교 예제입니다.

-- TimescaleDB: 하이퍼테이블 생성 및 시계열 쿼리
CREATE TABLE sensor_data (
  time TIMESTAMPTZ NOT NULL,
  sensor_id INTEGER NOT NULL,
  temperature DOUBLE PRECISION,
  humidity DOUBLE PRECISION
);

-- 하이퍼테이블로 변환 (7일 단위 파티셔닝)
SELECT create_hypertable('sensor_data', 'time',
  chunk_time_interval => INTERVAL '7 days');

-- 연속 집계 (Materialized View 자동 갱신)
CREATE MATERIALIZED VIEW sensor_hourly
WITH (timescaledb.continuous) AS
SELECT
  time_bucket('1 hour', time) AS hour,
  sensor_id,
  AVG(temperature) AS avg_temp,
  MAX(temperature) AS max_temp,
  MIN(temperature) AS min_temp
FROM sensor_data
GROUP BY hour, sensor_id;

-- 자동 갱신 정책
SELECT add_continuous_aggregate_policy('sensor_hourly',
  start_offset => INTERVAL '3 hours',
  end_offset => INTERVAL '1 hour',
  schedule_interval => INTERVAL '1 hour');

-- 압축 정책 (7일 이상 된 데이터 자동 압축)
ALTER TABLE sensor_data SET (
  timescaledb.compress,
  timescaledb.compress_segmentby = 'sensor_id'
);
SELECT add_compression_policy('sensor_data', INTERVAL '7 days');
-- QuestDB: 시계열 전용 문법
CREATE TABLE sensor_data (
  time TIMESTAMP,
  sensor_id SYMBOL,
  temperature DOUBLE,
  humidity DOUBLE
) timestamp(time) PARTITION BY DAY WAL;

-- SAMPLE BY: 시간 버킷 집계
SELECT
  time,
  sensor_id,
  avg(temperature) AS avg_temp,
  max(temperature) AS max_temp
FROM sensor_data
WHERE time IN '2024-01-01T00:00:00Z;7d'
SAMPLE BY 1h
FILL(PREV);

-- LATEST ON: 각 센서의 최신 값
SELECT * FROM sensor_data
LATEST ON time PARTITION BY sensor_id;

-- ASOF JOIN: 시간 기반 근사 조인
SELECT s.time, s.temperature, w.wind_speed
FROM sensor_data s
ASOF JOIN weather_data w ON (s.sensor_id = w.station_id);
# InfluxDB 3.0: Python 클라이언트
from influxdb_client_3 import InfluxDBClient3

client = InfluxDBClient3(
    host="https://us-east-1-1.aws.cloud2.influxdata.com",
    token="my-token",
    database="sensors"
)

# 라인 프로토콜로 데이터 입력 (고성능)
client.write([
    "sensor_data,sensor_id=S001 temperature=23.5,humidity=65.2",
    "sensor_data,sensor_id=S002 temperature=21.8,humidity=70.1",
])

# SQL로 쿼리
result = client.query("""
    SELECT
        date_bin('1 hour', time) AS hour,
        sensor_id,
        AVG(temperature) AS avg_temp
    FROM sensor_data
    WHERE time >= now() - INTERVAL '24 hours'
    GROUP BY hour, sensor_id
    ORDER BY hour DESC
""")
df = result.to_pandas()

활용 팁

  • 선택 기준: 기존 PostgreSQL 인프라가 있다면 TimescaleDB, 순수 시계열 워크로드라면 QuestDB, 클라우드 관리형이 필요하면 InfluxDB Cloud를 추천합니다.
  • 데이터 보존 정책: 시계열 데이터는 시간이 지날수록 가치가 감소합니다. TimescaleDB의 retention_policy, InfluxDB의 bucket retention으로 자동 삭제 정책을 설정하세요.
  • 다운샘플링: 원본 데이터는 일정 기간만 보존하고, 집계된 데이터(1분 -> 1시간 -> 1일)를 장기 보존하면 저장 비용을 크게 절감할 수 있습니다.
  • 배치 입력: 시계열 데이터는 반드시 배치로 입력하세요. 건별 INSERT 대비 100배 이상의 성능 차이가 납니다. QuestDB의 ILP, InfluxDB의 라인 프로토콜이 최적화되어 있습니다.
  • Grafana 연동: 세 DB 모두 Grafana 데이터소스를 지원합니다. 실시간 모니터링 대시보드 구축에 Grafana + 시계열 DB 조합이 사실상 표준입니다.

마무리

시계열 데이터베이스의 선택은 기존 인프라, 데이터 규모, 쿼리 패턴에 따라 달라집니다. TimescaleDB는 PostgreSQL 생태계의 친숙함, QuestDB는 극한의 성능, InfluxDB는 클라우드 편의성이 각각의 강점입니다. IoT, 모니터링, 금융 등 시계열 데이터가 핵심인 도메인에서는 범용 DB 대신 전문 시계열 DB를 도입하는 것이 장기적으로 훨씬 효율적입니다.