Files
2nd/10_Wiki/Topic_Programming/Coding/DB_Time_Series_Patterns.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

4.6 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
db-time-series-patterns Time-series — TimescaleDB / 다운샘플 / 보존 Coding draft B conceptual 2026-05-09 2026-05-09
database
time-series
timescale
vibe-coding
language applicable_to
Postgres / TimescaleDB / InfluxDB
Backend
time-series
TimescaleDB
hypertable
continuous aggregate
retention policy

Time-series Patterns

메트릭 / 이벤트 / 로그 / IoT = time-series. TimescaleDB (Postgres extension) 가 modern 표준 — 일반 SQL + 시간축 최적화. InfluxDB / Prometheus 도 옵션.

📖 핵심 개념

  • Hypertable: 시간 기준 자동 파티션.
  • Continuous aggregate: 실시간 materialized view (1m / 1h / 1d 다운샘플).
  • Compression: 오래된 chunk 자동 압축 (10-30x).
  • Retention policy: N일 후 자동 drop.

💻 코드 패턴

TimescaleDB hypertable

CREATE EXTENSION IF NOT EXISTS timescaledb;

CREATE TABLE metrics (
  time TIMESTAMPTZ NOT NULL,
  device_id TEXT NOT NULL,
  cpu DOUBLE PRECISION,
  mem DOUBLE PRECISION
);

SELECT create_hypertable('metrics', 'time', chunk_time_interval => INTERVAL '1 day');

CREATE INDEX metrics_device_time ON metrics(device_id, time DESC);

Insert (대량)

COPY metrics FROM STDIN;
-- 또는 multi-row INSERT
INSERT INTO metrics(time, device_id, cpu, mem)
VALUES ('2026-05-09 10:00', 'd1', 0.5, 0.3),
       ('2026-05-09 10:01', 'd1', 0.6, 0.3);

Query (시간 범위)

-- 최근 1시간
SELECT time_bucket('1 minute', time) AS bucket,
       device_id,
       avg(cpu) AS avg_cpu
FROM metrics
WHERE time > NOW() - INTERVAL '1 hour'
GROUP BY bucket, device_id
ORDER BY bucket;

Continuous aggregate

CREATE MATERIALIZED VIEW metrics_hourly
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 hour', time) AS hour,
       device_id,
       avg(cpu) AS avg_cpu,
       max(cpu) AS max_cpu,
       count(*) AS samples
FROM metrics
GROUP BY hour, device_id;

-- refresh 정책 (실시간으로 따라옴)
SELECT add_continuous_aggregate_policy('metrics_hourly',
  start_offset => INTERVAL '3 hours',
  end_offset => INTERVAL '5 minutes',
  schedule_interval => INTERVAL '5 minutes');

Compression

ALTER TABLE metrics SET (
  timescaledb.compress,
  timescaledb.compress_segmentby = 'device_id',
  timescaledb.compress_orderby = 'time DESC'
);

SELECT add_compression_policy('metrics', INTERVAL '7 days');
-- 7일 지난 chunk 자동 압축

Retention

SELECT add_retention_policy('metrics', INTERVAL '90 days');
-- 90일 지난 chunk 자동 drop

Time-bucket gap fill

SELECT time_bucket_gapfill('1 minute', time) AS bucket,
       device_id,
       locf(avg(cpu)) AS cpu  -- last observation carried forward
FROM metrics
WHERE time > NOW() - INTERVAL '1 hour'
  AND time <= NOW()
GROUP BY bucket, device_id;

Downsampling 단계

raw (1s) → 1분 (cont. agg) → 1시간 → 1일

각 단계는 다른 retention.

InfluxDB (alternative)

# Line protocol
metrics,device=d1 cpu=0.5,mem=0.3 1715238000000000000
// Flux 쿼리
from(bucket: "default")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "metrics")
  |> aggregateWindow(every: 1m, fn: mean)

Prometheus (메트릭 + 알람)

# scrape config
scrape_configs:
- job_name: api
  static_configs:
  - targets: ['api:9090']

PromQL:

rate(http_requests_total[5m])
histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))

🤔 의사결정 기준

데이터 추천
메트릭 + alert Prometheus + Grafana
IoT / 센서 (장기 보관) TimescaleDB
트레이딩 / 분석 TimescaleDB / ClickHouse
단순 events Postgres + 파티션
매우 큰 (PB) ClickHouse / Druid
짧은 (실시간 30일) Prometheus / InfluxDB

안티패턴

  • 단일 테이블 1B+ rows 일반 PG: 인덱스 거대, query 느림.
  • Index time + device 따로: composite (device, time DESC) 가 best.
  • Retention 없음: 영원 자라남.
  • Compression 미사용: 디스크 5-10x 더.
  • Continuous agg 없음 — raw 매번: 분 단위 query 가 시간.
  • Time as TEXT: 정렬 안 됨, range 쿼리 느림. TIMESTAMPTZ.
  • Monitoring DB 에 트랜잭션: HFT app + monitoring 같은 PG = 맥 끊김.

🤖 LLM 활용 힌트

  • TimescaleDB = Postgres 알면 그대로.
  • Hypertable + cont agg + compression + retention 4종.
  • Time-bucket + gapfill + locf 활용.

🔗 관련 문서