행 타임스탬프로 파이프라인 지연 시간 측정하기

행 타임스탬프로 파이프라인 지연 시간 측정하기

행 타임스탬프(row timestamps)는 테이블의 각 행이 마지막으로 업데이트된 정확한 시간순 기록을 제공해요. 같은 트랜잭션에서 수정된 행은 정확히 같은 타임스탬프를 공유하고, 다른 트랜잭션에서 수정된 행은 커밋된 시간 순서대로 정렬돼요.

주요 사용 사례는 다음과 같아요:

  • 파이프라인 관측성(pipeline observability): 클라이언트 측 타임스탬프보다 높은 정확도로 스트리밍 수집(streaming ingest), CDC, ETL 워크로드의 종단 간(end-to-end) 지연 시간과 데이터 신선도(data freshness)를 측정해요.
  • 신뢰할 수 있는 증분 처리: 이벤트 타임스탬프가 놓칠 수 있는 지연되거나 백필(backfill)된 레코드를 확정적인 커밋 시간을 사용해 포착해요.
  • 확정적인 감사 추적(audit trail): 규제 준수나 SCD2 방식의 마일스토닝(milestoning)을 위해 이벤트의 시간순을 확립해요.

테이블에 행 타임스탬프를 설정하려면 다음 옵션 중 하나를 선택하세요:

  • 테이블 또는 동적 테이블에 행 타임스탬프 설정: 테이블에 OWNERSHIP 권한이 있는 역할을 사용해 CREATE TABLE, ALTER TABLE, CREATE DYNAMIC TABLE, 또는 ALTER DYNAMIC TABLE 명령을 실행할 때 ROW_TIMESTAMP 속성을 TRUE로 설정해요. 예: CREATE TABLE … ROW_TIMESTAMP = TRUE, ALTER TABLE … SET ROW_TIMESTAMP = TRUE, 또는 ALTER DYNAMIC TABLE … SET ROW_TIMESTAMP = TRUE.
  • 컨테이너의 새 테이블에 기본적으로 행 타임스탬프 설정: 컨테이너에 ROW_TIMESTAMP_DEFAULT 속성을 TRUE로 설정해요. 예: ALTER SCHEMA … SET ROW_TIMESTAMP_DEFAULT = TRUE는 매개 변수를 설정한 후 스키마에서 생성되는 모든 새 테이블이 기본적으로 행 타임스탬프를 갖게 해요.
  • 기존 테이블에 대량으로 행 타임스탬프 활성화: SELECT SYSTEM$SET_ROW_TIMESTAMP_ON_ALL_SUPPORTED_TABLES 시스템 함수를 사용해요. 예: SELECT SYSTEM$SET_ROW_TIMESTAMP_ON_ALL_SUPPORTED_TABLES('schema', '{my_db}.my_schema'). 첫 번째 인자는 레벨로 schema, database, account 중 하나예요. 두 번째 인자는 컨테이너의 완전 수식 이름(FQN)이에요. 이 함수는 컨테이너 내 모든 기존 적격 테이블에 행 타임스탬프 컬럼을 추가하고, 새로 생성되는 테이블이 자동으로 행 타임스탬프가 활성화되도록 보장해요. 이 함수를 성공적으로 실행하려면 함수를 호출하는 컨테이너에 MODIFY 권한이 필요해요.

행 타임스탬프가 활성화되면 테이블은 각 행이 마지막으로 수정된 타임스탬프를 반환하는 METADATA$ROW_LAST_COMMIT_TIME 컬럼을 노출해요. 이를 통해 행 수정 시간을 기준으로 변경 추적(change tracking), 증분 처리, 타임 트래블(time-travel) 쿼리가 가능해져요.

📌 데이터 공유 시나리오에서 생산자(producer) 테이블에 행 타임스탬프가 활성화되어 있어도 소비자(consumer)는 METADATA$ROW_LAST_COMMIT_TIME을 선택할 수 없어요. 생산자가 소비자와 행 타임스탬프를 공유하려면 METADATA$ROW_LAST_COMMIT_TIME을 선택하는 뷰를 만든 다음 그 뷰를 공유해야 해요.

다음 문들은 행 타임스탬프를 지원하는 테이블을 만드는 방법을 보여줘요. 문들은 테이블에 데이터를 삽입하고 각 행의 타임스탬프를 검색해요.

CREATE OR REPLACE TABLE table1 (value1 STRING)
  ROW_TIMESTAMP = TRUE;

INSERT INTO table1 VALUES ('some-value-a');

INSERT INTO table1 VALUES ('some-value-b');

SELECT METADATA$ROW_LAST_COMMIT_TIME AS row_timestamp, *
  FROM table1
  ORDER BY 1;

본문

주요 사용 사례

METADATA$ROW_LAST_COMMIT_TIME 메타데이터 컬럼은 지연 시간 추적에 도움을 줘요. 예를 들어 총 5초 지연 시간을 목표로 한다면 이 컬럼이 Snowflake가 그 지연 시간에 기여하는 부분을 파악하게 해줘요.

주요 사용 사례는 다음과 같아요:

  • 수집 지연 시간 측정: 클라이언트에서 행이 생성된 시점과 Snowflake에 보이게 되는 시점 사이의 시간을 추적해 사용자가 데이터 수집 시간을 계산할 수 있게 해요.
  • 종단 간 지연 시간 측정: 수집 지연 시간과 파이프라인 지연 시간을 결합해 데이터 생성부터 최종 상태까지의 총 시간을 측정해요.
  • 파이프라인 지연 시간 측정: 데이터가 파이프라인을 통해 이동할 때 타임스탬프를 추적해요. 초기 테이블의 타임스탬프와 최종 테이블의 타임스탬프를 비교하면 파이프라인이 데이터를 처리하는 데 걸리는 시간을 측정할 수 있어요. 스트림, 동적 테이블, 태스크 기반 파이프라인에서 지원돼요.

예시: 수집 지연 시간 측정

METADATA$ROW_LAST_COMMIT_TIME 메타데이터 컬럼으로 수집 지연 시간을 측정하려면 다음을 수행하세요:

  1. 다음 방법 중 하나로 Snowflake에 데이터를 보내는 수집 파이프라인을 만들어요: Snowpipe Streaming Ingest SDK. 클라이언트 SDK로 Snowpipe Streaming 애플리케이션을 빌드하는 간단한 예시는 이 Java 파일(GitHub)을 참조하세요. 또는 Snowpipe COPY INTO <table> 명령.
  2. 다음을 실행해요: ALTER SESSION SET TIMESTAMP_TZ_OUTPUT_FORMAT = 'YYYY-MM-DDTHH:MI:SS.FF3 TZH'; ALTER SESSION SET TIMEZONE = 'UTC'; CREATE OR REPLACE DATABASE mydb; CREATE OR ALTER SCHEMA myschema; CREATE OR REPLACE TABLE table1 (record_id STRING, client_timestamp TIMESTAMP_LTZ); — 이 지점까지 server-side-insert-1에서 삽입된 행은 유효한 METADATA$ROW_LAST_COMMIT_TIME 타임스탬프를 갖지 않아요. INSERT INTO table1 VALUES ('server-side-insert-1', current_timestamp());
  3. 테이블을 수정해 METADATA$ROW_LAST_COMMIT_TIME 기능을 활성화해요. ALTER TABLE table1 SET ROW_TIMESTAMP = TRUE;
  4. 1단계에서 정의한 수집 파이프라인을 사용해 record_id와 client_timestamp 컬럼을 포함한 데이터를 Snowflake 테이블로 수집해요.
  5. 수집 파이프라인을 사용하지 않는다면 즉시 예시로 새 행을 삽입해요. 2단계의 삽입과 달리 이 삽입은 테이블 속성이 활성화되어 있으므로 유효한 METADATA$ROW_LAST_COMMIT_TIME 타임스탬프를 가져요. INSERT INTO table1 VALUES ('server-side-insert-2', current_timestamp());
  6. 클라이언트 측 프로그램을 다시 실행한 다음 다음을 수행해요: SELECT *, METADATA$ROW_LAST_COMMIT_TIME AS ROW_TIMESTAMP, TIMESTAMPDIFF(ms, CLIENT_TIMESTAMP, ROW_TIMESTAMP) AS INGEST_LATENCY FROM table1 ORDER BY 2;

예시: 동적 테이블로 파이프라인 지연 시간 측정

행 타임스탬프는 동적 테이블에서 지원돼요. 소스 테이블과 동적 테이블 모두에 ROW_TIMESTAMP를 활성화하면 데이터가 소스 테이블에서 동적 테이블로 흐르는 데 걸리는 시간인 파이프라인 지연 시간을 측정할 수 있어요.

다음 예시는 소스 테이블을 만들고, 데이터를 삽입하고, 소스 행 타임스탬프를 구체화하는 동적 테이블을 만들고, 동적 테이블을 갱신(refresh)한 다음 쿼리해 파이프라인 지연 시간을 계산해요.

  1. 행 타임스탬프가 활성화된 소스 테이블을 만들고 데이터를 삽입해요: CREATE OR REPLACE TABLE raw_events (event_id INT, event_type STRING, event_data STRING) ROW_TIMESTAMP = TRUE; INSERT INTO raw_events VALUES (1, 'click', '{"page":"home"}'), (2, 'view', '{"page":"product"}');
  2. 소스 테이블의 METADATA$ROW_LAST_COMMIT_TIME을 컬럼으로 구체화하는 동적 테이블을 만들어요. 동적 테이블 자체에도 ROW_TIMESTAMP를 활성화해 고유한 METADATA$ROW_LAST_COMMIT_TIME을 갖게 해요: CREATE OR REPLACE DYNAMIC TABLE processed_events TARGET_LAG = '1 minute' WAREHOUSE = my_warehouse REFRESH_MODE = INCREMENTAL ROW_TIMESTAMP = TRUE AS SELECT event_id, event_type, event_data, METADATA$ROW_LAST_COMMIT_TIME AS source_last_commit_time FROM raw_events;
  3. 삽입된 행을 처리하도록 동적 테이블을 갱신해요: ALTER DYNAMIC TABLE processed_events REFRESH;
  4. 동적 테이블을 쿼리해 파이프라인 지연 시간을 측정해요. source_last_commit_time 컬럼은 각 행이 소스 테이블에서 커밋된 시점을, 동적 테이블의 고유 METADATA$ROW_LAST_COMMIT_TIME은 동적 테이블 갱신이 그 행을 커밋한 시점을 기록해요: SELECT event_id, event_type, source_last_commit_time, METADATA$ROW_LAST_COMMIT_TIME AS dt_last_commit_time, TIMESTAMPDIFF('second', source_last_commit_time, METADATA$ROW_LAST_COMMIT_TIME) AS pipeline_latency_seconds FROM processed_events ORDER BY event_id;

예시: 커밋 시간을 기준으로 행 만료 또는 아카이브

스토리지 수명 주기 정책(storage lifecycle policy)이 METADATA$ROW_LAST_COMMIT_TIME을 평가할 수 있으므로, 자체 타임스탬프 컬럼을 유지하지 않고 커밋 시간 기준으로 행을 보존할 수 있어요.

다음 예시는 마지막 커밋 후 90일이 지난 행을 COOL 스토리지로 아카이브한 다음, 추가로 365일 후 아카이브에서 만료시켜요. 만료 전용 정책은 ARCHIVE_TIER와 ARCHIVE_FOR_DAYS를 생략해요.

CREATE OR REPLACE STORAGE LIFECYCLE POLICY retain_by_commit_time
  AS (commit_time TIMESTAMP)
  RETURNS BOOLEAN
  ->
    TO_DATE(commit_time) < TO_DATE(DATEADD(DAY, -90, CURRENT_TIMESTAMP()))
  ARCHIVE_TIER = COOL
  ARCHIVE_FOR_DAYS = 365;

ALTER TABLE events
  ADD STORAGE LIFECYCLE POLICY retain_by_commit_time
  ON (METADATA$ROW_LAST_COMMIT_TIME);

보조 사용 사례

행 타임스탬프는 다음 경우에도 사용할 수 있어요:

  • 데이터 보존: 자체 last-modified 컬럼을 유지하지 않고 METADATA$ROW_LAST_COMMIT_TIME에 스토리지 수명 주기 정책을 연결해 오래된 행을 자동으로 만료하거나 아카이브하고 스토리지 비용을 절약해요.
  • 이벤트 순서 지정과 변경 추적: 행 타임스탬프로 변경을 추적할 수 있어요. 가장 큰 타임스탬프를 가진 행이 가장 최근 변경을 나타내요.
  • 추가 전용 데이터(append-only): 행이 추가만 된다면 행 타임스탬프가 특정 시점의 테이블 상태를 걸러 내는 데 도움이 되어, 데이터 보존 정책과 관계없이 타임 트래블(Time Travel)을 사용할 수 있게 해요.

제한 사항과 고려 사항

  • 행 타임스탬프는 같은 테이블 안에서만 시간순 유지가 보장돼요(장애 조치(failover)의 경우 순서가 보장되지 않아요). 테이블 간, 다른 리전 간, 또는 다른 시간 소스 간 정렬은 보장되지 않아요. 행 타임스탬프를 다른 테이블이나 소스와 비교하면 안 돼요. 불일치가 생길 수 있기 때문이에요.
  • 행 타임스탬프는 생성 시간이 아니라 마지막 업데이트 시간을 반영해요. 예를 들어 데이터 행이 커밋 후 업데이트되면 행 타임스탬프는 데이터의 생성 시간이 아니라 마지막 업데이트 시간을 반영해요.
  • 테이블에 행 타임스탬프가 활성화되기 전에 생성된 행의 타임스탬프는 NULL로 설정돼요.
  • 행 타임스탬프는 행이 저장되는 동안 계속 저장돼요.
  • ROW_TIMESTAMP 속성을 FALSE로 설정하면 저장된 모든 METADATA$ROW_LAST_COMMIT_TIME 값이 영구적으로 삭제돼요. 다시 활성화해도 복원되지 않으며 타임 트래블 쿼리는 아무것도 반환하지 않아요.
  • 행 타임스탬프는 Apache Iceberg™ 테이블, 외부 테이블, 하이브리드 테이블, 스트림, 뷰에서 지원되지 않아요.
  • METADATA$ROW_LAST_COMMIT_TIME 메타데이터 컬럼은 다음에서 참조할 수 없어요: CHANGES 절, 행 접근 정책과 컬럼 접근(마스킹) 정책, 제약 조건(constraints), CLUSTER BY 표현식.
  • 스토리지 수명 주기 정책은 METADATA$ROW_LAST_COMMIT_TIME을 참조할 수 있어요. 만료 및 아카이브 정책이 모두 지원되므로 자체 타임스탬프 컬럼을 유지하는 대신 마지막 커밋 시간을 기준으로 행을 만료하거나 아카이브할 수 있어요. 이 기능은 동적 테이블에서는 지원되지 않아요. METADATA$ROW_LAST_COMMIT_TIME을 참조하는 정책을 동적 테이블에 연결하면 지원되지 않는 기능 오류가 반환돼요.
  • 행 타임스탬프는 아카이브 테이블 복원(archive table restore)으로 복원할 수 없어요. 해결 방법으로 METADATA$ROW_LAST_COMMIT_TIME을 다른 테이블의 유지 컬럼(persisted column)으로 구체화해 아카이브 복원에 사용할 수 있어요.

행 타임스탬프의 클론 고려 사항

테이블 클론은 행 타임스탬프를 정확히 보존해요. CREATE TABLE AS SELECT(CTAS)와 INSERT INTO … SELECT처럼 데이터의 물리적 복사본을 만드는 작업은 복사가 만들어진 시점을 반영하는 새 행 타임스탬프를 할당해요. 소스 테이블의 원래 행 타임스탬프는 보존되지 않아요. 이를 기록으로 남기고 싶다면 다음 예시처럼 명시적으로 유지 컬럼으로 선택하세요.

CREATE TABLE my_archive AS
  SELECT *, METADATA$ROW_LAST_COMMIT_TIME AS original_commit_time
  FROM my_source_table;

더 알아보기 (Learn more)