BTP

HANA 파티셔닝 Hash vs Range vs RoundRobin #shorts #SAP #HANA

1. 대용량 테이블의 조회 성능 문제 — 왜 파티셔닝이 필요한가

SAP HANA 컬럼 스토어 테이블은 인메모리 구조 덕분에 기본 조회 성능이 뛰어나지만, 데이터가 수억 건 단위로 쌓이기 시작하면 상황이 달라집니다. 가장 먼저 부딪히는 것은 단일 컬럼 스토어 테이블(또는 파티션)당 약 20억 건(2,147,483,648 rows)의 하드 리밋입니다. 이 한도에 도달하면 INSERT 자체가 실패하므로, 대용량 트랜잭션 테이블은 언젠가 반드시 분할이 필요합니다.

한도에 도달하기 전에도 문제는 나타납니다. 델타 머지(Delta Merge)가 테이블 전체 단위로 수행되면서 머지 시간이 길어지고, 특정 시점의 CPU/메모리 스파이크가 커집니다. 또한 전체 테이블 스캔이 필요한 쿼리는 데이터 양에 비례해 느려지고, 여러 노드로 구성된 스케일아웃 환경에서는 한 노드에만 부하가 몰리는 현상도 발생합니다.

이 글에서는 HANA가 제공하는 대표적인 3가지 파티셔닝 방식 — Range, Hash, RoundRobin — 의 동작 원리와 선택 기준을 SalesOrder 실무 시나리오 기반 예제로 살펴봅니다. 대상 환경은 SAP HANA 2.0 SPS 05 이상이며, SAP HANA Cloud에서도 동일한 문법이 일반적으로 적용됩니다.

2. SAP HANA 파티셔닝 개념과 동작 원리

파티셔닝은 논리적으로 하나인 테이블을 물리적으로 여러 조각(파티션)으로 나누는 기술입니다. 애플리케이션 입장에서는 여전히 하나의 테이블로 보이므로 SQL 변경이 필요 없습니다. 도서관에 비유하면, 책 100만 권을 한 서가에 몰아넣는 대신 출간 연도별·주제별로 여러 서가에 나눠 꽂아두는 것과 같습니다. 사서(옵티마이저)는 요청을 보고 필요한 서가만 뒤지면 됩니다.

파티셔닝이 성능에 기여하는 핵심 메커니즘은 세 가지입니다.

  • Partition Pruning — WHERE 조건이 파티셔닝 컬럼을 포함하면 옵티마이저가 관련 없는 파티션을 스캔 대상에서 제외합니다. 스캔 범위가 1/N로 줄어듭니다.
  • 병렬 처리 — 여러 파티션을 여러 코어(또는 여러 노드)가 동시에 스캔할 수 있습니다.
  • 델타 머지 분산 — 머지가 파티션 단위로 수행되어, 변경이 발생한 파티션만 머지됩니다. 머지 비용과 락 경합이 크게 줄어듭니다.

파티셔닝은 단일 레벨(Single-Level)다중 레벨(Multi-Level)로 구성할 수 있습니다. 단일 레벨에서 Hash·Range 방식을 쓰려면 파티셔닝 컬럼이 기본 키(Primary Key)의 일부여야 한다는 제약이 있습니다. 이 제약을 우회해야 할 때(예: 키가 아닌 날짜 컬럼으로 Range 분할) 1차 Hash + 2차 Range 같은 다중 레벨 조합이 일반적으로 사용됩니다.

3. Range 파티셔닝 — 날짜/범위 기반 데이터 분할

Range 파티셔닝은 값의 구간을 지정해 데이터를 나눕니다. 회계연도, 주문일자, 문서번호 대역처럼 데이터가 시간 축을 따라 쌓이는 패턴에 가장 잘 맞습니다.

CREATE COLUMN TABLE SALES_ORDER (
    ORDER_ID      NVARCHAR(10) NOT NULL,
    ORDER_DATE    DATE         NOT NULL,
    CUSTOMER_ID   NVARCHAR(10),
    NET_AMOUNT    DECIMAL(15,2),
    CURRENCY      NVARCHAR(5),
    PRIMARY KEY (ORDER_ID, ORDER_DATE)
)
PARTITION BY RANGE (ORDER_DATE) (
    PARTITION '2024-01-01' <= VALUES < '2025-01-01',
    PARTITION '2025-01-01' <= VALUES < '2026-01-01',
    PARTITION '2026-01-01' <= VALUES < '2027-01-01',
    PARTITION OTHERS
);

이렇게 만들면 WHERE ORDER_DATE >= '2026-01-01' 같은 조건에서 2024·2025년 파티션은 아예 스캔되지 않습니다(Pruning). PARTITION OTHERS는 정의된 구간 밖의 값을 받아주는 안전망으로, 이것이 없으면 범위 밖 INSERT가 실패하므로 일반적으로 함께 정의하는 것이 권장됩니다.

Range의 또 다른 강점은 수명주기 관리입니다. 오래된 연도 파티션을 통째로 DROP하거나, HANA의 Data Tiering과 연계해 저비용 저장소로 내리는 운영이 파티션 단위로 가능합니다. 반면 단점도 뚜렷합니다. 최근 날짜 파티션에 INSERT가 집중되는 Hot Partition 현상이 생길 수 있고, 새 구간을 주기적으로 추가하는 관리 작업이 필요합니다.

4. Hash 파티셔닝 — 균등 분산으로 Hot Spot 제거

Hash 파티셔닝은 지정한 컬럼 값에 해시 함수를 적용해 데이터를 N개 파티션에 균등하게 흩뿌립니다. 특정 파티션에 부하가 몰리지 않으므로, 스케일아웃 환경에서 노드 간 부하 분산이 목적일 때 가장 일반적으로 선택됩니다.

CREATE COLUMN TABLE SALES_ORDER_ITEM (
    ORDER_ID     NVARCHAR(10) NOT NULL,
    ITEM_NO      INTEGER      NOT NULL,
    MATERIAL_ID  NVARCHAR(18),
    QUANTITY     DECIMAL(13,3),
    ITEM_AMOUNT  DECIMAL(15,2),
    PRIMARY KEY (ORDER_ID, ITEM_NO)
)
PARTITION BY HASH (ORDER_ID) PARTITIONS 8;

여기서 두 가지 설계 포인트가 중요합니다.

  • 파티셔닝 컬럼 선택 — 카디널리티가 높은 컬럼이어야 균등 분산이 됩니다. ORDER_ID는 적합하지만, 값 종류가 5개뿐인 상태 코드 컬럼은 부적합합니다.
  • 조인 코로케이션 — 헤더(SALES_ORDER)와 아이템(SALES_ORDER_ITEM)을 같은 컬럼(ORDER_ID)·같은 파티션 수로 Hash 분할하면, 스케일아웃에서 두 테이블의 같은 주문 데이터가 같은 노드에 배치되어 노드 간 데이터 이동 없이 로컬 조인이 가능합니다.

PARTITIONS GET_NUM_SERVERS() 구문을 쓰면 노드 수에 맞춰 파티션 수를 자동 결정할 수도 있습니다. 단, Hash는 값 기반 Pruning이 동등 조건(ORDER_ID = 'SO0001234')에서만 동작하고, 범위 조건이나 다른 컬럼 조건에서는 전 파티션을 스캔한다는 점을 기억해야 합니다.

5. RoundRobin 파티셔닝 — 단순 순차 분산의 활용

RoundRobin은 들어오는 로우를 파티션 1 → 2 → 3 → … 순서로 돌아가며 배정하는 가장 단순한 방식입니다. 카드를 플레이어에게 한 장씩 돌리는 것과 같아서 분산은 완벽하게 균등하지만, 어떤 값이 어느 파티션에 있는지 시스템이 알 수 없습니다.

CREATE COLUMN TABLE INTERFACE_LOG (
    LOG_ID      BIGINT,
    IF_NAME     NVARCHAR(30),
    PAYLOAD     NCLOB,
    CREATED_AT  TIMESTAMP
)
PARTITION BY ROUNDROBIN PARTITIONS 4;

특징을 정리하면 다음과 같습니다.

  • 기본 키가 없는 테이블에만 적용 가능합니다(키가 있으면 Hash/Range 사용).
  • 값과 파티션의 매핑이 없으므로 Partition Pruning이 전혀 동작하지 않습니다. 모든 조회는 전 파티션 스캔입니다.
  • 대신 파티셔닝 컬럼 선정 고민 없이 INSERT 부하와 20억 건 한도를 즉시 분산할 수 있습니다.

따라서 RoundRobin은 인터페이스 로그, 스테이징 영역처럼 선별 조회보다 대량 적재가 중심인 키 없는 테이블에 한정적으로 활용하는 것이 일반적입니다. 조회 패턴이 있는 업무 테이블에 쓰는 것은 권장되지 않습니다.

6. 3가지 방식 비교 — 상황별 선택 기준

구분RangeHashRoundRobin
분산 균등성데이터 패턴에 의존 (Hot Partition 가능)높음 (카디널리티 충분 시)완전 균등
Partition Pruning범위·동등 조건 모두 지원동등 조건만 지원불가
기본 키 제약파티셔닝 컬럼이 PK 포함 필요파티셔닝 컬럼이 PK 포함 필요PK 없는 테이블만
수명주기 관리파티션 단위 DROP/아카이빙 용이어려움어려움
대표 용도시계열 트랜잭션, 아카이빙 대상스케일아웃 분산, 조인 코로케이션키 없는 로그/스테이징

실무 판단 순서를 요약하면 이렇습니다. (1) 날짜·기간 조건 조회와 보존 정책이 있는 테이블 → Range. (2) 특정 키 동등 조회가 많고 부하 분산이 목적 → Hash. (3) 키가 없고 적재만 빠르면 되는 테이블 → RoundRobin. (4) 두 요구가 겹치면 — 예를 들어 노드 분산도 필요하고 연도별 아카이빙도 필요하다면 — Hash + Range 다중 레벨이 일반적인 해법입니다. 다중 레벨의 2차 Range 컬럼은 PK가 아니어도 되므로 설계 자유도가 높아집니다.

7. 실전 예제 — SalesOrder 대용량 테이블 파티셔닝 적용

연 3억 건이 쌓이는 판매오더 테이블을 가정하고, Hash(1차) + Range(2차) 다중 레벨을 적용하는 과정을 단계별로 진행합니다.

1단계 — 현재 상태 진단. 파티셔닝 전 테이블 크기와 로우 수를 확인합니다.

SELECT TABLE_NAME, RECORD_COUNT,
       ROUND(MEMORY_SIZE_IN_TOTAL/1024/1024/1024, 2) AS SIZE_GB
FROM   M_CS_TABLES
WHERE  SCHEMA_NAME = 'SALES'
AND    TABLE_NAME  = 'SALES_ORDER_HDR';

2단계 — 다중 레벨 파티셔닝 적용. 기존 테이블은 ALTER로 재파티셔닝할 수 있습니다. 1차는 ORDER_ID Hash 4개, 2차는 ORDER_DATE 연도 Range입니다.

ALTER TABLE SALES.SALES_ORDER_HDR
PARTITION BY HASH (ORDER_ID) PARTITIONS 4,
             RANGE (ORDER_DATE) (
                 PARTITION '2024-01-01' <= VALUES < '2025-01-01',
                 PARTITION '2025-01-01' <= VALUES < '2026-01-01',
                 PARTITION '2026-01-01' <= VALUES < '2027-01-01',
                 PARTITION OTHERS
             );

이 명령은 전체 데이터를 재배치하므로 시간이 오래 걸리고 상당한 메모리를 사용합니다. 대용량 테이블은 반드시 업무 외 시간에 수행하고, 사전에 여유 메모리를 확인하는 것이 권장됩니다. HANA 2.0 SPS 04 이상에서는 온라인 재파티셔닝 옵션도 검토할 수 있습니다.

3단계 — 새 연도 파티션 운영. 매년 말, 다음 연도 구간을 추가합니다. OTHERS 파티션이 있는 상태에서 구간을 추가하면 OTHERS에 쌓인 해당 구간 데이터가 새 파티션으로 이동합니다.

ALTER TABLE SALES.SALES_ORDER_HDR
ADD PARTITION '2027-01-01' <= VALUES < '2028-01-01';

-- 보존 기한 경과 파티션 제거 (아카이빙 완료 후)
ALTER TABLE SALES.SALES_ORDER_HDR
DROP PARTITION '2024-01-01' <= VALUES < '2025-01-01';

4단계 — 파티션 배치 확인.

SELECT PART_ID, RECORD_COUNT, LEVEL_1_TYPE, LEVEL_2_TYPE
FROM   M_TABLE_PARTITIONS
WHERE  SCHEMA_NAME = 'SALES'
AND    TABLE_NAME  = 'SALES_ORDER_HDR'
ORDER  BY PART_ID;

파티션별 RECORD_COUNT가 크게 치우쳐 있다면 Hash 컬럼의 카디널리티나 Range 구간 설계를 재검토해야 합니다.

8. 파티셔닝 후 성능 검증 및 주의사항

적용 후에는 반드시 Pruning이 실제로 동작하는지 실행 계획으로 검증합니다.

EXPLAIN PLAN FOR
SELECT ORDER_ID, NET_AMOUNT
FROM   SALES.SALES_ORDER_HDR
WHERE  ORDER_DATE BETWEEN '2026-01-01' AND '2026-06-30';

SELECT OPERATOR_NAME, TABLE_NAME, PARTITION_INFO
FROM   EXPLAIN_PLAN_TABLE;

PARTITION_INFO에 전체가 아닌 일부 파티션 번호만 표시되면 Pruning이 정상 동작하는 것입니다. PlanViz(HANA Studio / Database Explorer)로 파티션별 스캔 시간을 비교하는 방법도 유용합니다.

자주 겪는 문제를 FAQ로 정리합니다.

  • Q1. 파티셔닝했는데 조회가 더 느려졌습니다. — WHERE 조건에 파티셔닝 컬럼이 없으면 Pruning 없이 N개 파티션을 모두 스캔하며, 파티션 결과 병합 오버헤드만 추가됩니다. 실제 조회 패턴의 필터 컬럼으로 설계했는지 재확인하세요.
  • Q2. 파티션 수는 몇 개가 적당한가요? — 무조건 많다고 좋지 않습니다. 파티션이 과도하면 메타데이터 관리·병합 비용이 커집니다. 일반적으로 파티션당 1억~3억 건 수준을 목표로, 향후 2~3년 증가분까지 고려해 산정하는 것이 권장됩니다.
  • Q3. Hash 파티셔닝 후 특정 파티션만 커집니다. — 파티셔닝 컬럼의 값 분포가 치우친 경우입니다. 카디널리티가 더 높은 컬럼으로 변경하거나, 복수 컬럼 Hash(HASH (ORDER_ID, ITEM_NO))를 검토하세요.
  • Q4. ALTER 재파티셔닝 중 메모리 부족이 발생했습니다. — 재파티셔닝은 원본과 대상 구조를 동시에 유지하므로 테이블 크기의 수 배 메모리가 필요할 수 있습니다. 대안으로 새 파티션 테이블을 만들어 INSERT ... SELECT로 구간별 이관 후 RENAME하는 방식이 있습니다.

댓글 0

아직 댓글이 없습니다.