Blog
trinoicebergparquetperformance

Trino + Iceberg 는 파티션 문제를 어떻게 해결하는가

Hive/Impala 에서 파티션 컬럼 누락 시 풀스캔이 발생하는 이유와, Trino + Iceberg 의 hidden partitioning·메타데이터 기반 프루닝이 이 문제를 구조적으로 제거하는 방법을 정리합니다.

Data Dynamics2026년 5월 30일25 min read

Trino 에서 Parquet 포맷의 Iceberg 테이블을 만들고, 같은 데이터를 Impala 와 Hive 에서도 조회할 수 있게 구성하는 것은 흔한 아키텍처입니다. 그런데 Impala 나 Hive 에서 쿼리를 날릴 때 WHERE 절에 파티션 컬럼을 빠뜨리면 수 TB 풀스캔이 발생하고 클러스터가 멈추는 경험을 한 적 있으신가요? 이 글은 Hive/Impala 에서 이 문제가 왜 구조적으로 피할 수 없는지, 그리고 Trino + Iceberg 가 어떻게 이 문제를 근본적으로 제거하는지를 다룹니다.

1. 문제: 파티션 컬럼을 빠뜨리면 클러스터가 멈춘다

Hive 와 Impala 에서 파티션 테이블을 만드는 전형적인 패턴입니다.

CREATE TABLE events (
  event_id    BIGINT,
  user_id     BIGINT,
  event_type  STRING,
  event_time  TIMESTAMP,
  city        STRING,
  payload     STRING
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET;

이 테이블에 1년치 데이터가 쌓여 있다고 가정합니다. 약 500GB, 365개 파티션.

-- 정상: 파티션 프루닝 동작, 하루치 약 1.4GB 만 스캔
SELECT * FROM events WHERE dt = '2026-04-12' AND user_id = 12345;
 
-- 문제: dt 파티션 컬럼 누락 → 365개 파티션 전체 스캔 (500GB)
SELECT * FROM events WHERE user_id = 12345;

두 번째 쿼리는 user_id 조건만 있고 dt 가 없습니다. Hive/Impala 는 어떤 파티션에 user_id = 12345 데이터가 있는지 알 방법이 없으므로, 모든 파티션의 모든 파일을 열어서 확인해야 합니다.

2. 왜 Hive/Impala 는 이 문제를 피할 수 없는가

디렉터리 기반 파티셔닝

Hive/Impala 의 파티션은 물리 디렉터리입니다.

/warehouse/events/dt=2026-04-01/
/warehouse/events/dt=2026-04-02/
/warehouse/events/dt=2026-04-03/
...
/warehouse/events/dt=2026-04-12/
  ├── 000000_0.parquet
  ├── 000001_0.parquet
  └── 000002_0.parquet

Hive Metastore(HMS)는 파티션 디렉터리 목록을 관리하지만, 각 파일 안에 어떤 데이터가 들어있는지(min/max 통계)는 모릅니다. 쿼리 플래너가 파티션을 줄이려면 WHERE 절에 파티션 컬럼(dt)이 명시적으로 있어야 합니다.

Strict Mode 로 막을 수는 있지만

Hive 는 hive.mapred.mode=strict, Impala 는 쿼리 옵션으로 파티션 컬럼이 없는 쿼리를 거부할 수 있습니다. 하지만 이것은 "실수를 차단" 하는 것이지, 파티션 컬럼 없이도 효율적으로 조회하는 것은 불가능합니다.

3. 파티션 개수 제한: Hive/Impala vs Trino+Iceberg

파티션을 잘게 나누면 쿼리 성능이 좋아지지만, Hive/Impala 에서는 파티션 수 자체가 병목이 됩니다.

Hive/Impala 의 파티션 제한

항목HiveImpala
파티션 컬럼 수제한 없음 (실무상 3~4개 권장)동일
최대 파티션 수HMS 성능 한계로 수만~수십만 개에서 심각한 저하Catalogd 메모리에 파티션 메타를 전부 올리므로 수십만 개 넘으면 OOM·갱신 지연
동적 파티션 생성 제한hive.exec.max.dynamic.partitions 기본값 1000MAX_DYNAMIC_PARTITIONS 쿼리 옵션으로 제한
플래닝 시 파티션 로드HMS 에 RPC → 파티션 수가 많으면 쿼리 플래닝만 수 분HDFS NameNode + Catalogd 동기화 비용 추가

파티션 컬럼을 2~3개 조합하면 카디널리티가 폭발합니다. 예를 들어 dt × region × device_type = 365 × 50 × 10 = 182,500 파티션/년. Hive/Impala 에서는 이런 설계를 할 수 없습니다.

Trino + Iceberg 의 파티션 제한

항목Trino + Iceberg
파티션 컬럼 수Iceberg spec 상 제한 없음
최대 파티션 수사실상 무제한. 파티션이 HMS 레코드가 아니라 manifest 내부 메타데이터
동적 파티션 생성 제한없음
플래닝 시 파티션 로드Manifest 파일만 읽으면 됨. HMS RPC 불필요

Iceberg 는 파티션 정보를 HMS 에 등록하지 않고 manifest 파일에 저장합니다. 따라서 파티션 수가 늘어나도 HMS 에 RPC 를 날리지 않으며, 100만 개 파티션이 있어도 manifest 프루닝으로 필요한 파일만 빠르게 필터링합니다.

비교 요약

항목Hive/ImpalaTrino + Iceberg
파티션 =HMS 레코드 + HDFS 디렉터리Manifest 내부 메타데이터
파티션 수 실무 한계수만~수십만 (이후 성능 저하)사실상 무제한
파티션 추가 비용HMS ALTER TABLE ADD PARTITION (RPC)데이터 쓰기 시 자동 반영 (manifest commit)
파티션 수 × 플래닝 시간선형 증가거의 일정
동적 파티션 생성 제한기본 1000개/쿼리없음

실무 시사점: Hive/Impala 에서는 시간 파티션을 일 단위가 한계이지만, Trino + Iceberg 에서는 hours(event_time) 파티션도 부담 없고, days(event_time), bucket(32, user_id) 같은 복합 파티션도 자유롭습니다.

4. Iceberg 가 다른 점: 메타데이터 기반 아키텍처

Iceberg 는 테이블 메타데이터를 3계층 구조로 관리합니다.

Metadata file (JSON)
  └── Snapshot
        └── Manifest list (Avro)
              └── Manifest file (Avro)
                    └── 개별 데이터 파일 정보
                          ├── 파일 경로
                          ├── 파티션 값
                          ├── row count
                          ├── 컬럼별 min / max
                          ├── null count
                          └── 파일 크기

핵심은 manifest file 입니다. 각 데이터 파일의 파티션 값과 컬럼별 min/max 통계가 manifest 안에 들어있으므로, 데이터 파일을 열지 않고도 "이 파일이 쿼리에 필요한지" 를 판단할 수 있습니다.

Hive/Impala 와의 근본적인 차이:

항목Hive/ImpalaIceberg
메타데이터 위치HMS (외부 RPC)Manifest 파일 (스토리지 직접 읽기)
파일 수준 통계없음 (파티션 단위만)min/max, null count, row count 등
파일 프루닝불가능Manifest 기반으로 가능

5. Hidden Partitioning — 사용자가 파티션을 몰라도 되는 구조

이것이 Iceberg 의 가장 큰 차별점입니다.

Hive 방식

-- 테이블 생성 시 파티션 컬럼을 스키마에 명시
CREATE TABLE events (...) PARTITIONED BY (dt STRING);
 
-- INSERT 시 파티션 값을 명시적으로 지정
INSERT INTO events PARTITION (dt = '2026-04-12') VALUES (...);
 
-- SELECT 시에도 파티션 컬럼을 WHERE 에 명시해야 프루닝
SELECT * FROM events WHERE dt = '2026-04-12';

사용자가 dt 라는 파티션 컬럼의 존재를 알고, INSERT/SELECT 모두에서 명시해야 합니다.

Iceberg 방식: Partition Transform

-- 파티션 컬럼이 스키마에 노출되지 않음
CREATE TABLE iceberg_catalog.db.events (
  event_id    BIGINT,
  user_id     BIGINT,
  event_type  VARCHAR,
  event_time  TIMESTAMP(6) WITH TIME ZONE,
  city        VARCHAR,
  payload     VARCHAR
)
WITH (
  format = 'PARQUET',
  partitioning = ARRAY['days(event_time)']
);

event_time 컬럼에서 자동으로 일 단위 파티션이 생성됩니다. 별도의 dt 파티션 컬럼이 스키마에 없습니다.

-- 사용자는 그냥 event_time 으로 조건을 걸면 됨
SELECT * FROM events
WHERE event_time >= TIMESTAMP '2026-04-12 00:00:00 UTC'
  AND event_time <  TIMESTAMP '2026-04-13 00:00:00 UTC';

Trino 가 days(event_time) partition transform 을 알고 있으므로, 자동으로 해당 일자의 파티션만 스캔합니다. 파티션 컬럼이 스키마에 없으니 빠뜨릴 일 자체가 없습니다.

지원되는 Partition Transform:

Transform설명예시
years(col)연 단위years(event_time)
months(col)월 단위months(event_time)
days(col)일 단위days(event_time)
hours(col)시간 단위hours(event_time)
bucket(N, col)해시 버킷 N개bucket(32, user_id)
truncate(W, col)문자열/숫자를 W 폭으로 잘라서 파티션truncate(10, city)

6. Trino + Iceberg 에서 파티션 컬럼이 꼭 필요한가?

결론: 필수는 아니다. 하지만 없으면 달라지는 것이 있다

Iceberg 테이블은 파티션 없이도 생성·조회가 가능합니다.

-- 파티션 없는 Iceberg 테이블
CREATE TABLE iceberg_catalog.db.events_no_partition (
  event_id    BIGINT,
  user_id     BIGINT,
  event_time  TIMESTAMP(6) WITH TIME ZONE,
  city        VARCHAR
)
WITH (format = 'PARQUET');

이 테이블에 WHERE event_time = TIMESTAMP '2026-04-12 10:00:00 UTC' 로 조회하면:

  1. Manifest 에 파티션 값이 없음 → 모든 manifest entry 를 확인
  2. 하지만 Parquet footer 의 column statistics(min/max)로 row group 단위 스킵은 가능
  3. 결과: 파일은 전부 열지만, row group 단위로 일부 스킵 → Hive 풀스캔보다는 낫지만, 파티션이 있을 때보다 훨씬 느림
구성파일 프루닝Row Group 프루닝전체 스캔 범위
파티션 없음불가Parquet min/max 로 일부 스킵거의 전체
파티션 있음 (hidden)Manifest 기반으로 대부분 스킵추가로 row group 스킵해당 파티션 파일만

파티션 컬럼이 아닌 컬럼을 WHERE 에 넣으면?

파티션은 days(event_time) 으로 설정했지만, 쿼리는 WHERE user_id = 12345 인 경우:

  1. Manifest 프루닝: user_id 는 파티션 transform 과 무관 → 파일을 줄일 수 없음 → 모든 데이터 파일이 후보
  2. Parquet min/max 프루닝: 각 파일의 user_id 컬럼 min/max 확인 → 범위 밖이면 스킵
  3. 실제 읽기: min/max 범위 안에 드는 파일만 열어서 row group 단위로 한 번 더 필터

결과: 파티션 프루닝 효과는 0, Parquet 통계에만 의존. 데이터가 정렬되어 있지 않으면 사실상 풀스캔에 가까움.

대응법:

-- 방법 1: user_id 에 대한 bucket 파티션 추가
ALTER TABLE events SET PROPERTIES
  partitioning = ARRAY['days(event_time)', 'bucket(64, user_id)'];
 
-- 방법 2: 정렬 키 설정으로 min/max 통계 효과 극대화
ALTER TABLE events SET PROPERTIES
  sorted_by = ARRAY['user_id'];
 
ALTER TABLE events EXECUTE optimize;

존재하지 않는 컬럼을 WHERE 에 넣으면?

SELECT * FROM events WHERE non_existent_column = 'value';
-- 결과: COLUMN_NOT_FOUND 에러로 즉시 쿼리 실패

Iceberg 스키마에 없는 컬럼이므로 플래닝 단계에서 거부됩니다. 이 동작은 Hive/Impala 도 동일합니다.

단, Schema Evolution 으로 나중에 추가된 컬럼의 경우, 추가 이전의 데이터 파일에는 해당 컬럼이 없으므로 NULL 로 처리됩니다. 쿼리 자체는 정상 실행됩니다.

7. Trino 의 파일 프루닝 메커니즘

Trino + Iceberg 는 3단계 깔때기로 불필요한 데이터를 걸러냅니다.

[전체 데이터 파일]


  ① Manifest 기반 프루닝
  (파티션 값 + 파일 수준 min/max)
       │  불필요한 파일 제거

  ② Parquet Row Group 프루닝
  (row group 별 column statistics)
       │  불필요한 row group 스킵

  ③ Dynamic Filtering
  (JOIN 의 build side 결과를 probe side 에 전파)
       │  추가로 파일/row group 스킵

  [실제로 읽는 데이터]

각 단계가 순차적으로 데이터를 줄이므로, 최종적으로 읽는 데이터량이 극적으로 감소합니다.

8. 실전 비교: 같은 데이터, 같은 쿼리, 다른 결과

시나리오 설정

  • 테이블: 1년치 이벤트 로그, 약 500GB
  • 파티션: 일 단위 (Hive: dt 컬럼, Iceberg: days(event_time))
  • Parquet 포맷

쿼리 1: 파티션 컬럼 명시

-- Hive/Impala
SELECT * FROM events WHERE dt = '2026-04-12' AND user_id = 12345;
 
-- Trino + Iceberg
SELECT * FROM events
WHERE event_time >= TIMESTAMP '2026-04-12 00:00:00 UTC'
  AND event_time <  TIMESTAMP '2026-04-13 00:00:00 UTC'
  AND user_id = 12345;
엔진스캔 범위비고
Hive/Impala~1.4GB (1일분)파티션 프루닝 정상 동작
Trino + Iceberg~1.4GB (1일분)Hidden partition 프루닝 동작

모두 빠릅니다.

쿼리 2: 파티션 컬럼 누락 — 시간 범위만

-- Hive/Impala: dt 를 안 쓰고 event_time 으로만 조건
SELECT * FROM events WHERE event_time >= '2026-04-12' AND event_time < '2026-04-13';
 
-- Trino + Iceberg: 동일한 조건
SELECT * FROM events
WHERE event_time >= TIMESTAMP '2026-04-12 00:00:00 UTC'
  AND event_time <  TIMESTAMP '2026-04-13 00:00:00 UTC';
엔진스캔 범위비고
Hive/Impala~500GB (전체)event_time 은 파티션 컬럼이 아니므로 풀스캔
Trino + Iceberg~1.4GB (1일분)days(event_time) transform 으로 자동 프루닝

350배 차이. Hive/Impala 에서는 풀스캔, Trino + Iceberg 에서는 하루치만 읽습니다.

쿼리 3: 파티션과 무관한 컬럼

SELECT * FROM events WHERE user_id = 12345;
엔진스캔 범위비고
Hive/Impala~500GB (전체)풀스캔
Trino + Iceberg (파티션: days(event_time) 만)~500GB (전체)user_id 는 파티션과 무관, Parquet min/max 에만 의존
Trino + Iceberg (파티션: days(event_time) + bucket(64, user_id))~7.8GB (1/64)bucket 파티션 프루닝

파티션 설계가 쿼리 패턴과 맞아야 효과가 있습니다.

쿼리 4: 파티션 없는 Iceberg 테이블

SELECT * FROM events_no_partition
WHERE event_time >= TIMESTAMP '2026-04-12 00:00:00 UTC'
  AND event_time <  TIMESTAMP '2026-04-13 00:00:00 UTC';
엔진스캔 범위비고
Trino + Iceberg (파티션 없음)거의 전체Parquet min/max 로 일부 row group 스킵, 파일 프루닝 불가
Trino + Iceberg (파티션 있음)~1.4GB파티션 프루닝으로 대부분 스킵

파티션 없는 Iceberg 도 Hive 풀스캔보다는 약간 낫지만, 파티션이 있을 때와는 10~50배 성능 차이가 납니다.

9. Iceberg 테이블 생성과 파티션 설정

기본 생성

CREATE TABLE iceberg_catalog.db.events (
  event_id    BIGINT,
  user_id     BIGINT,
  event_type  VARCHAR,
  event_time  TIMESTAMP(6) WITH TIME ZONE,
  city        VARCHAR,
  payload     VARCHAR
)
WITH (
  format = 'PARQUET',
  partitioning = ARRAY['days(event_time)']
);

복합 파티션

CREATE TABLE iceberg_catalog.db.events (
  event_id    BIGINT,
  user_id     BIGINT,
  event_type  VARCHAR,
  event_time  TIMESTAMP(6) WITH TIME ZONE,
  city        VARCHAR
)
WITH (
  format = 'PARQUET',
  partitioning = ARRAY['days(event_time)', 'bucket(32, user_id)']
);

Partition Evolution — 기존 데이터 재작성 없이 파티션 전략 변경

Iceberg 고유 기능입니다. Hive/Impala 에서는 불가능합니다.

-- 기존: 일 단위 파티션
-- 변경: 시간 단위 파티션으로 전환
ALTER TABLE events SET PROPERTIES
  partitioning = ARRAY['hours(event_time)'];

이후 새로 쓰이는 데이터만 시간 단위 파티션을 적용받고, 기존 데이터는 일 단위 파티션 그대로 유지됩니다. Iceberg 의 manifest 가 파티션 spec 버전을 추적하므로 혼재된 상태에서도 프루닝이 정상 동작합니다.

10. Trino + Iceberg 에서도 성능이 나빠지는 경우

Trino + Iceberg 가 만능은 아닙니다. 다음 상황에서는 성능이 크게 저하됩니다.

10.1 Small File Problem

Iceberg 는 파티션 수 제한이 없는 대신, INSERT 가 잦으면 파티션당 수백~수천 개의 작은 파일이 쌓입니다. 각 파일마다 manifest entry 가 존재하고, Parquet footer 를 파일마다 열어야 하므로 파일 수 × I/O 오버헤드가 발생합니다.

증상: 데이터 양은 적은데 쿼리 플래닝이 수십 초 걸림.

-- 작은 파일 병합 (컴팩션)
ALTER TABLE events EXECUTE optimize;
 
-- 또는 WHERE 조건으로 특정 파티션만 컴팩션
ALTER TABLE events EXECUTE optimize
  WHERE event_time >= TIMESTAMP '2026-04-01 00:00:00 UTC'
    AND event_time <  TIMESTAMP '2026-05-01 00:00:00 UTC';

10.2 Manifest 비대화

파일 수가 수십만 개를 넘으면 manifest 자체를 읽는 시간이 늘어납니다.

-- 파일 수 확인
SELECT count(*) AS file_count,
       sum(file_size_in_bytes) / (1024*1024*1024) AS total_gb
FROM "events$files";

10.3 Predicate Pushdown 이 안 되는 WHERE 조건

WHERE 절에 컬럼을 함수로 감싸면 predicate pushdown 이 깨집니다.

패턴Pushdown설명
WHERE event_time = TIMESTAMP '...'O직접 비교
WHERE CAST(event_time AS DATE) = DATE '...'X함수 적용 → 풀스캔
WHERE year(event_time) = 2026X함수 래핑 → 풀스캔
WHERE LOWER(city) = 'seoul'X문자열 함수 → 풀스캔
WHERE city LIKE '%eoul'X앞쪽 와일드카드 → min/max 활용 불가
WHERE city IN ('Seoul', 'Busan')OIN 리스트 → pushdown 가능
WHERE event_time BETWEEN ... AND ...O범위 비교 → pushdown + partition 프루닝

핵심 규칙: 컬럼은 항상 왼쪽에 단독으로, 변환은 오른쪽(상수 쪽)에서 처리.

-- BAD: pushdown 안 됨
WHERE CAST(event_time AS DATE) = DATE '2026-04-12'
 
-- GOOD: pushdown 됨
WHERE event_time >= TIMESTAMP '2026-04-12 00:00:00 UTC'
  AND event_time <  TIMESTAMP '2026-04-13 00:00:00 UTC'

10.4 정렬되지 않은 데이터

Parquet row group 의 min/max 통계는 데이터가 정렬되어 있을 때 효과적입니다.

  • 정렬된 경우: row group 1 은 user_id 1~1000, row group 2 는 1001~2000WHERE user_id = 500 이면 row group 1만 읽음
  • 비정렬 경우: 모든 row group 의 user_id 범위가 1~100000 으로 겹침 → 전부 읽어야 함
-- 정렬 키 설정
ALTER TABLE events SET PROPERTIES
  sorted_by = ARRAY['user_id'];
 
-- 기존 데이터 재정렬
ALTER TABLE events EXECUTE optimize;

10.5 JOIN 시 Dynamic Filtering 미작동

Dynamic Filtering 이 작동하지 않는 조건:

  • Build side 결과가 너무 클 때 (수십만 건 이상) → dynamic filter 생성 포기
  • LEFT JOIN / FULL OUTER JOIN → probe side 를 줄일 수 없음
  • JOIN 키가 파티션 컬럼과 무관할 때

10.6 과도한 스냅샷 누적

Iceberg 는 매 쓰기마다 새 스냅샷을 생성합니다. 시간이 지나면 수천 개의 스냅샷이 쌓이고, metadata file 크기 증가로 플래닝이 느려집니다.

-- 오래된 스냅샷 만료
ALTER TABLE events EXECUTE expire_snapshots(retention_threshold => '7d');
 
-- 고아 파일 제거
ALTER TABLE events EXECUTE remove_orphan_files(retention_threshold => '7d');

10.7 Worker 메모리 부족

파티션/파일 수와 무관하게, 대량 데이터를 집계·조인하면 Worker 메모리가 초과됩니다. Trino 는 디스크로 spill 가능하지만 성능이 크게 저하됩니다.

대응:

  • query.max-memory-per-node 조정
  • SELECT * 지양, 필요한 컬럼만 지정
  • 대량 집계는 단계별로 분리

11. 성능 확보를 위한 추가 팁

항목설정/명령효과
통계 수집ANALYZE eventsTrino 플래너가 더 나은 실행 계획 생성
Row group 크기write.parquet.row-group-size-bytes적절한 크기로 row group 프루닝 효과 조정
정렬 키sorted_by = ARRAY['col']min/max 통계 범위를 좁혀서 프루닝 효과 극대화
컴팩션ALTER TABLE ... EXECUTE optimize작은 파일 병합, 정렬 적용
스냅샷 관리EXECUTE expire_snapshotsmetadata 크기 감소
고아 파일 제거EXECUTE remove_orphan_files불필요한 스토리지 회수

12. 성능 저하 진단 체크리스트

문제가 발생했을 때 아래 순서로 확인하세요.

순서확인 항목확인 방법
1WHERE 절에 함수가 감싸져 있지 않은가쿼리 리뷰
2파일/파티션 프루닝이 동작하는가EXPLAIN (TYPE DISTRIBUTED)
3작은 파일이 과다하지 않은가SELECT count(*), sum(file_size_in_bytes) FROM "table$files"
4데이터가 정렬되어 있는가sorted_by 속성 확인
5스냅샷이 과도하게 쌓여 있지 않은가SELECT count(*) FROM "table$snapshots"
6Dynamic Filtering 이 동작하는가EXPLAIN 에서 dynamicFilter 존재 여부
7Worker 메모리가 충분한가Trino Web UI → Query Detail → Stage 별 메모리

13. 정리

항목Hive/ImpalaTrino + Iceberg
파티션 구조디렉터리 기반, HMS 관리Manifest 기반, HMS 무관
파티션 컬럼 누락 시풀스캔Hidden partitioning 으로 자동 프루닝
파티션 수 한계수만~수십만사실상 무제한
파일 수준 프루닝불가능Manifest 의 min/max 통계로 가능
파티션 전략 변경테이블 재생성 필요Partition Evolution 으로 무중단 변경
동적 파티션 생성 제한있음 (기본 1000)없음

Hive/Impala 의 파티션 문제는 "사용자의 실수" 가 아니라 디렉터리 기반 파티셔닝의 구조적 한계입니다. Iceberg 는 메타데이터 계층을 테이블 포맷 안으로 가져옴으로써 이 한계를 근본적으로 제거했고, Trino 는 이 메타데이터를 최대한 활용하여 불필요한 I/O 를 줄입니다.

다만 Trino + Iceberg 도 만능은 아닙니다. Small file problem, predicate pushdown 이 깨지는 SQL 패턴, 비정렬 데이터, 스냅샷 누적 등은 여전히 성능을 저하시킵니다. EXPLAIN 으로 실행 계획을 확인하고, 정기적인 컴팩션과 스냅샷 관리를 습관화하는 것이 핵심입니다.


이 글은 Trino 443 + Iceberg spec v2 기준으로 작성되었습니다. 실제 환경에서의 파티션 설계나 마이그레이션에 대해 도움이 필요하시면 언제든 문의해 주세요.

— Data Dynamics 엔지니어링 팀