SAP

Column Engine vs Row Engine — HANA Calculation View 설계 핵심 #shorts #SAP #HANA

▶ YouTube에서 보기

1. 개요 및 이 글에서 다룰 것

SAP HANA Calculation View는 인메모리 컬럼 스토어 위에서 동작하는 가상 데이터 모델로, 잘못 설계하면 수십 GB 메모리를 소모하거나 응답 시간이 수십 초까지 늘어날 수 있습니다. 반대로 노드 순서와 Cardinality, Filter 위치만 제대로 잡아도 동일한 쿼리가 수백 ms 안에 끝납니다. 본 글은 Projection → Filter → Join → Aggregation이라는 기본 설계 패턴을 따라가며, 왜 그 순서가 권장되는지, 어떤 옵션을 어디서 켜야 하는지를 SAP HANA Cloud 및 HANA 2.0 SPS07 기준으로 정리합니다.

본 글에서 다룰 것:

  • Column Engine이 좋아하는 노드 구조와 그렇지 않은 구조의 차이
  • Projection 노드에서 컬럼을 줄이고 상수 필터를 미리 적용하는 방법
  • Join 방향, Cardinality(n:1, 1:1), Left Outer 사용 시 주의점
  • Aggregation 노드를 최상단에 두고 Input Parameter를 Push-down 하는 방법
  • Row Engine으로 떨어지는 흔한 실수와 PlanViz로 확인하는 절차

2. 사전 가정

본 글은 SAP HANA Studio 또는 Business Application Studio에서 HDI 컨테이너 기반 Calculation View(.hdbcalculationview)를 한 번이라도 만들어 본 독자를 가정합니다. SQL Join, GROUP BY, 서브쿼리의 의미를 알고 있어야 하며, 컬럼 스토어와 로우 스토어의 차이, Star Join 모델링의 기본 개념도 가볍게 알고 있으면 좋습니다. ABAP CDS와 HANA Calculation View의 차이는 다루지 않고, 순수 HANA 모델링 관점에서만 설명합니다.

3. 환경 / 버전 / 준비물

실습에 사용하는 환경은 다음과 같습니다.

  • SAP HANA Cloud QRC 2/2026 또는 SAP HANA 2.0 SPS07
  • SAP Business Application Studio — SAP HANA Database Extension 설치
  • HDI Container — cf create-service hana hdi-shared로 생성
  • SAP HANA Database Explorer — SQL 실행 및 PlanViz 확인용
  • 샘플 데이터: SALES_ORDER(약 1억 건), CUSTOMER(50만 건), PRODUCT(2만 건)

권장 사양은 모델링 워크스테이션 기준 16GB RAM 이상, HANA 인스턴스는 최소 30GB 메모리를 가진 개발용 인스턴스를 사용합니다. 라이선스 측면에서는 Runtime Calculation View 기준이며, Graphical Calculation View(CUBE with Star Join, DIMENSION) 타입을 중심으로 다룹니다. SQL Script Calculation View는 일반적으로 마지막 수단으로 두는 편이 좋습니다.

4. 핵심 개념

SAP HANA의 데이터 처리 엔진은 크게 Column Engine(OLAP Engine 포함)Row Engine, 그리고 SQL Engine / JoinEngine으로 나뉩니다. Calculation View는 가능하면 Column Engine 안에서 모든 연산을 끝내려고 합니다. Column Engine은 컬럼 단위로 압축된 메모리 블록을 SIMD 명령으로 한 번에 스캔하기 때문에, 컬럼 수가 적고 필터가 일찍 들어올수록 빨라집니다. 반대로 노드 사이에 데이터 타입이 맞지 않거나, 복잡한 SQL 함수가 끼면 중간에 Row Engine으로 데이터를 옮기는 materialization이 일어나면서 성능이 급격히 떨어집니다.

이때 기억할 비유는 "좁은 깔때기"입니다. 깔때기 위에 큰 통(원본 테이블)이 있고, 아래로 내려갈수록 좁아지는 형태가 이상적입니다. 즉 가장 아래(Source) 가까이에서 컬럼을 줄이고 필터를 걸어 데이터를 좁히고, 위로 올라갈수록 가벼운 상태로 Join과 Aggregation을 수행하는 것입니다. 거꾸로 위에서 필터를 거는 구조는 큰 통을 그대로 들어 올렸다가 마지막에 부어버리는 셈이라 메모리와 CPU를 낭비합니다.

그래서 권장되는 노드 배치는 다음과 같습니다.

              [Aggregation]      (최상단, GROUP BY와 Input Parameter)
                   |
                [Join]            (Cardinality 명시, 작은 쪽이 우측)
               /      \
        [Projection] [Projection] (컬럼 최소화 + Filter Push-down)
             |              |
        [Table/CV]     [Table/CV] (Source 가까이)

여기서 핵심은 세 가지입니다. 첫째, Projection은 Source 바로 위에 둔다. 둘째, Join은 Cardinality를 명시하고 방향을 통제한다. 셋째, Aggregation은 최상단에 한 번만 둔다. 이 원칙만 지켜도 대부분의 모델이 Column Engine 안에서 처리됩니다.

5. 실전 설계

5-1단계: Projection 노드로 컬럼 최소화 (기본 예제)

Projection 노드는 SQL의 SELECT 절과 WHERE 절을 합친 역할을 합니다. Source 테이블에 컬럼이 80개 있어도, 모델에서 실제 쓰는 것은 6~7개뿐인 경우가 많습니다. Projection에서 사용하지 않는 컬럼을 모두 제거하면 Column Engine이 디스크/메모리에서 읽어야 할 블록이 줄어듭니다. 동시에 상수 비교 필터(예: COMPANY_CODE = '1000')도 Projection 단계에서 걸어 두면 Join 이전에 데이터가 좁혀집니다.

-- Calculation View가 생성하는 내부 쿼리(개념적 표현)
SELECT CUSTOMER_ID, ORDER_DATE, NET_AMOUNT, CURRENCY
FROM   SALES.SALES_ORDER
WHERE  COMPANY_CODE = '1000'
  AND  ORDER_DATE  >= ADD_DAYS(CURRENT_DATE, -365);

Graphical Editor에서는 Projection 노드 우측의 Mapped Columns에서 필요한 컬럼만 끌어다 놓고, Filter Expression에 위 WHERE 조건을 입력합니다. 이때 함수는 가능하면 컬럼 엔진 친화적인 것(=, IN, BETWEEN, ADD_DAYS)을 씁니다.

5-2단계: Join 방향과 Cardinality 설정 (실무 시나리오)

두 번째 단계는 Join입니다. SAP HANA Calculation View에서 Join 노드는 두 입력을 받는데, 일반적으로 큰 테이블(팩트)을 좌측, 작은 테이블(차원)을 우측에 두는 것이 권장됩니다. 그리고 Cardinality를 n:1 또는 1:1로 명시해야 옵티마이저가 Join Pruning과 Unfolding을 수행할 수 있습니다. Cardinality를 비워 두면 옵티마이저는 안전을 위해 두 쪽 모두 실체화해야 하므로 성능이 떨어집니다.

-- Star Join 형태가 권장되는 구조
SELECT  s.ORDER_DATE,
        c.COUNTRY,
        p.CATEGORY,
        SUM(s.NET_AMOUNT) AS REVENUE
FROM    SALES_ORDER  s                 -- 팩트, 좌측
LEFT OUTER JOIN CUSTOMER c              -- n:1, 우측
   ON   s.CUSTOMER_ID = c.CUSTOMER_ID
LEFT OUTER JOIN PRODUCT  p              -- n:1, 우측
   ON   s.PRODUCT_ID  = p.PRODUCT_ID
GROUP BY s.ORDER_DATE, c.COUNTRY, p.CATEGORY;

Graphical Editor에서는 Join 노드 속성창에서 다음을 설정합니다.

  • Join Type: Referential Join을 우선 검토. 외래키 무결성이 보장된다면 Inner Join보다 Pruning이 잘 됩니다.
  • Cardinality: 팩트 쪽 N, 차원 쪽 1 (n:1)
  • Optimize Join Columns: 체크. SELECT 절에서 사용되지 않는 Join Key는 결과에서 제거됩니다.
  • Dynamic Join: 차원 컬럼이 항상 쿼리에 포함되지 않을 때 유용. 단, 항상 포함되어야 하는 경우 일반 Join이 더 빠릅니다.

로깅 측면에서는 SAP HANA Database Explorer에서 Analyze SQL → Explain Plan / PlanViz를 실행해, 각 Join이 JECalculator 또는 OLAP Search로 처리되는지 확인합니다. 만약 Row Search가 나타나면 Cardinality 누락 또는 데이터 타입 불일치가 원인일 가능성이 높습니다.

5-3단계: Aggregation 최상단 + Input Parameter (프로덕션)

세 번째 단계는 Aggregation입니다. 최상단에 한 번만 두고, Input Parameter를 통해 사용자 입력 필터를 Projection까지 Push-down 하도록 설계합니다. 이렇게 하면 사용자가 "2026년 6월, 한국 법인"만 조회할 때 그 조건이 가장 아래 Projection까지 전달되어, 처음부터 좁은 데이터만 읽게 됩니다.

-- Input Parameter 사용 예 (HANA Calculation View SQL 인터페이스)
SELECT  ORDER_DATE,
        COUNTRY,
        CATEGORY,
        REVENUE
FROM    "SALES_CV/CV_SALES_REVENUE"
        ( 'PLACEHOLDER' = ('$$IP_COMPANY_CODE$$' , '1000'),
          'PLACEHOLDER' = ('$$IP_YEAR_MONTH$$'  , '202606') )
WHERE   COUNTRY = 'KR';

Calculation View 내부에서는 Projection 노드의 Filter Expression에 다음과 같이 Input Parameter를 참조합니다.

"COMPANY_CODE" = '$$IP_COMPANY_CODE$$'
AND LEFT("ORDER_DATE", 6) = '$$IP_YEAR_MONTH$$'

프로덕션 단계에서는 다음을 함께 고려합니다.

  • Cache Invalidation: Result Cache를 활성화한 경우, Input Parameter 조합별로 캐시가 생성되므로 카디널리티가 너무 높은 파라미터는 캐시 효율이 떨어집니다.
  • Default Schema/Apply Privileges: Analytic Privilege를 활성화해 행 단위 보안을 적용합니다. 권장적으로 USER_NAME, COMPANY_CODE 등 자주 쓰는 필터 컬럼 기준으로 정의합니다.
  • Unit Test: hana-cli 또는 HDI 빌드 후 Data Preview에서 PlanViz 결과를 캡처하고, 응답 시간/Records Transferred 값을 회귀 테스트 항목으로 관리합니다.
  • Aggregation Behavior: COUNTER/SUM/AVG 등 집계 타입을 명시하고, Calculated Column은 가능하면 Aggregation 노드 위에서 정의합니다.

6. 흔한 실수 / 트러블슈팅

Calculation View 성능 문제의 80%는 비슷한 패턴에서 발생합니다. 자주 만나는 사례를 FAQ 형태로 정리합니다.

Q1. 분명 Filter를 걸었는데 PlanViz에서는 Source 테이블을 전체 스캔합니다. 왜죠?
A. Filter Expression에 Column Engine이 지원하지 않는 함수(예: 사용자 정의 함수, 복잡한 정규식, TO_VARCHAR 변환 후 비교)가 들어가면 Push-down이 막힙니다. 또한 Calculated Column을 기준으로 필터를 걸 때 그 Calculated Column이 비결정적(non-deterministic)이면 동일한 현상이 발생합니다. 가능한 한 원본 컬럼을 그대로 비교하고, 변환이 필요하면 Input Parameter 단에서 미리 변환해 넘기는 방식을 권장합니다.

Q2. Join을 추가했더니 갑자기 Row Engine으로 떨어집니다.
A. 두 입력의 Join Key 데이터 타입이 다른 경우(예: NVARCHAR vs VARCHAR, INTEGER vs DECIMAL)가 흔한 원인입니다. HANA가 내부적으로 CAST를 끼우면서 Row Engine을 거치게 됩니다. 또 한 가지는 Left Outer Join에서 우측에 또 다른 Join이 중첩된 구조입니다. 이 경우 Cardinality가 모호해져 옵티마이저가 보수적으로 동작합니다. 데이터 타입을 통일하고, 중첩 Join은 Star Join 모델로 평탄화하는 것을 권장합니다.

Q3. Aggregation 노드를 여러 개 쌓아도 되나요?
A. 일반적으로 권장되지 않습니다. 중간 Aggregation은 머터리얼라이즈를 강제하므로, 위쪽 노드에서 추가 필터/Join이 들어와도 더 이상 Push-down 되지 않습니다. 정말 필요한 경우(예: 두 단계 평균)에만 사용하고, 가능하면 Calculated Column과 Exception Aggregation을 활용해 한 번에 끝내는 편이 빠릅니다.

그 외 점검 포인트로는 (1) Keep Flag가 불필요하게 켜져 있어 컬럼 Pruning이 막히는 경우, (2) Currency Conversion 노드가 매 행마다 호출되는 경우, (3) Variable과 Input Parameter를 혼동해 Filter Push-down이 안 되는 경우 등이 있습니다. 의심될 때는 항상 PlanViz로 실제 실행 계획을 확인하는 것이 가장 빠른 길입니다.

7. 다음 단계 / 관련 주제

여기까지 따라왔다면 단일 Calculation View의 기본 성능 튜닝은 가능합니다. 다음 학습 주제로는 아래를 권장합니다.

  • Star Join과 Shared Dimension: 여러 팩트가 같은 차원을 참조할 때 재사용 가능한 차원 뷰 설계
  • Rank Node와 Window Function: Top-N, 최신 레코드 추출 시 SQL Script 대신 그래픽 노드로 처리
  • Result Cache, Static Cache: 자주 호출되는 모델의 응답 속도 안정화
  • Analytic Privileges: 사용자별 행 단위 보안 적용
  • SAP HANA Cloud의 HDI 기반 CI/CD: mta.yaml로 모델 자동 배포

8. 핵심 한 줄

아래에서 좁히고, 가운데서 붙이고, 위에서 모은다. Projection으로 컬럼과 행을 줄이고, Join은 Cardinality를 명시해 작은 쪽을 우측에 두며, Aggregation은 최상단에 한 번만 두고 Input Parameter로 필터를 끝까지 밀어내는 것 — 이것이 SAP HANA Calculation View 성능 설계의 출발점입니다.

참고 자료

댓글 0

아직 댓글이 없습니다.