-- P1a: 1초 링버퍼 히스토리안 (hc900.history_1s) -- 적용: psql "host=localhost dbname=iiot_platform user=postgres" -f scripts/sql/p1_historian.sql -- 서비스(Hc900FastHistoryService)가 기동 시 동일 DDL을 멱등 적용하므로 수동 실행은 선택. SET search_path TO hc900; CREATE TABLE IF NOT EXISTS hc900.history_1s ( tagname text NOT NULL, recorded_at timestamptz NOT NULL DEFAULT now(), value text, controller_id text ); -- 하이퍼테이블 (1시간 청크 — evict/압축 단위) SELECT create_hypertable('hc900.history_1s', 'recorded_at', chunk_time_interval => INTERVAL '1 hour', if_not_exists => TRUE); -- 압축 (6시간 지난 청크) + 링버퍼 보존 (14일 — 청크 DROP, 비용≈0) ALTER TABLE hc900.history_1s SET (timescaledb.compress, timescaledb.compress_segmentby = 'tagname'); SELECT add_compression_policy('hc900.history_1s', INTERVAL '6 hours', if_not_exists => TRUE); SELECT add_retention_policy('hc900.history_1s', INTERVAL '14 days', if_not_exists => TRUE); CREATE INDEX IF NOT EXISTS ix_h1s_tag ON hc900.history_1s (tagname, recorded_at DESC); -- P1b: 연속집계 history_1min — 1초 버퍼 evict 전 60초 롤업(장기 무손실, 2계층) CREATE MATERIALIZED VIEW IF NOT EXISTS hc900.history_1min WITH (timescaledb.continuous) AS SELECT time_bucket('1 minute', recorded_at) AS bucket, tagname, last(value, recorded_at) AS value, last(controller_id, recorded_at) AS controller_id FROM hc900.history_1s GROUP BY bucket, tagname WITH NO DATA; -- 집계 lag(≤3h) ≪ 보존 윈도(14일) → raw 삭제 전 materialize 보장 SELECT add_continuous_aggregate_policy('hc900.history_1min', start_offset => INTERVAL '3 hours', end_offset => INTERVAL '10 minutes', schedule_interval => INTERVAL '5 minutes', if_not_exists => TRUE); -- P1c: 메트릭엔진 드롭인 소스(bucket→recorded_at) + 온라인 KPI 누적 테이블 CREATE OR REPLACE VIEW hc900.history_1min_src AS SELECT tagname, bucket AS recorded_at, value, controller_id FROM hc900.history_1min; CREATE TABLE IF NOT EXISTS hc900.live_kpi ( column_id text NOT NULL, kpi text NOT NULL, window_start date NOT NULL, value double precision, unit text, state text, excluded_min int, status text, updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (column_id, kpi, window_start));