들어가며 — 왜 CDS 성능 힌트가 중요한가
HANA 기반 ABAP 개발에서 CDS 뷰는 단순한 SELECT 래퍼가 아닙니다. ABAP RAP, Fiori Elements, OData 서비스의 모든 데이터 흐름이 CDS를 통과하기 때문에, 뷰 한 개의 실행 계획이 어긋나면 화면 로딩이 5초에서 30초로 늘어나는 일이 흔합니다. 특히 수천만 건 규모의 헤더·아이템 조인이나 통화 환산이 들어간 분석용 뷰에서는, 옵티마이저가 잘못된 조인 순서를 선택하거나 불필요한 풀스캔을 수행하는 경우가 자주 관찰됩니다.
이런 상황에서 개발자가 옵티마이저에게 의도를 알려주는 도구가 바로 성능 힌트(Performance Hint)입니다. ABAP CDS는 어노테이션 기반 힌트와 ABAP SQL 레벨의 %_HINTS 구문을 함께 제공합니다. 어느 쪽이든 핵심은 같습니다. 옵티마이저가 통계 정보만으로는 결정을 내리기 어려운 영역, 예를 들어 데이터 분포가 비대칭이거나 트랜잭션과 분석 워크로드가 섞인 영역에서, 개발자의 도메인 지식을 실행 계획에 주입하는 것입니다.
이번 글에서는 ABAP Platform 2022 이상(S/4HANA 2022/2023 포함)에서 실무에 바로 적용 가능한 세 가지 힌트를 다룹니다. 첫째 @AbapCatalog.buffering으로 테이블 버퍼 활성화, 둘째 %_HINTS HANA로 옵티마이저에 인덱스 접근 강제, 셋째 @ObjectModel.usageType으로 뷰의 목적과 크기를 선언하는 방법입니다.
사전 점검 — 힌트를 쓰기 전에 확인할 것
성능 힌트는 "마지막 카드"입니다. 힌트를 추가하기 전에 다음을 먼저 확인하는 것이 권장됩니다.
- SQL Monitor(트랜잭션
SQLM)와 SQL Trace(ST05)로 실제 병목 식별 - SAT(런타임 분석)로 ABAP 측 루프와 DB 측 비용 분리
- HANA Plan Visualizer(PlanViz)로 옵티마이저가 선택한 실행 계획 검토
- 인덱스·통계 갱신 상태(
DB02) 점검
이 과정 없이 힌트부터 박으면, 데이터 분포가 바뀌었을 때 오히려 성능이 급락하는 역효과가 발생합니다. 힌트는 옵티마이저보다 개발자가 더 잘 안다는 가정이 성립할 때만 의미가 있습니다.
환경과 버전 전제
아래 예제는 다음 환경을 기준으로 작성되었습니다.
- ABAP Platform 2022 이상 (ABAP Cloud / On-Premise 공통)
- S/4HANA 2022 또는 2023, SAP BTP ABAP Environment 2308 이상
- HANA DB 2.0 SPS07 이상
- ADT(ABAP Development Tools) for Eclipse 3.36 이상
- CDS View Entity 문법 (구버전 DDIC-based
define view가 아닌define view entity)
참고로 %_HINTS 구문은 ABAP Cloud의 Released API 환경에서는 제한이 있을 수 있어, 사용 전 Release Contract를 반드시 확인하는 것이 일반적입니다.
핵심 개념 — 옵티마이저와 개발자의 역할 분담
HANA 옵티마이저를 "고속도로 내비게이션"에 비유하면 이해가 쉽습니다. 평소에는 실시간 교통 정보(통계)를 보고 최적 경로를 찾지만, 공사 구간이나 일시적 폐쇄처럼 통계가 반영되지 못한 상황에서는 운전자(개발자)가 직접 경로를 지정해야 합니다.
CDS 힌트는 크게 세 층위에서 동작합니다.
- 저장 계층: 테이블 버퍼링(
@AbapCatalog.buffering)으로 DB 왕복 자체를 제거 - 실행 계획 계층:
%_HINTS HANA로 조인 순서, 인덱스 접근, 병렬화 등 직접 제어 - 메타데이터 계층:
@ObjectModel.usageType으로 뷰의 의도(트랜잭션/분석/혼합)를 옵티마이저와 RAP 런타임에 전달
이 세 가지는 서로 배타적이지 않고 함께 사용됩니다. 예를 들어 마스터 데이터 뷰는 버퍼링을, 분석용 뷰는 usageType 선언을, 병목 트랜잭션 쿼리는 %_HINTS를 적용하는 식의 조합이 일반적입니다.
힌트 1 — @AbapCatalog.buffering으로 뷰 버퍼링 활성화
첫 번째 힌트는 자주 읽히고 거의 변경되지 않는 뷰에 적용하는 테이블 버퍼링입니다. 국가 텍스트, 통화 코드, 단위, 회사 코드 마스터처럼 읽기가 압도적인 데이터가 대표적인 후보입니다.
버퍼링 유형은 세 가지가 있습니다. #SINGLE은 키별로 단건 캐싱, #GENERIC은 일반 키 일부 기준 묶음 캐싱, #FULL은 테이블 전체를 버퍼에 적재합니다. 텍스트 테이블처럼 언어·키 조합으로 조회가 잦은 경우 #SINGLE이 일반적으로 적합합니다.
@AbapCatalog.sqlViewName: 'ZICOUNTRY'
@AbapCatalog.buffering.status: #ACTIVE
@AbapCatalog.buffering.type: #SINGLE
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Country Master with Buffering'
define view entity ZI_Country
as select from t005t
{
key spras as Language,
key land1 as Country,
landx as CountryName,
natio as Nationality
}
버퍼링이 활성화되면 동일 키 조회 시 ST10에서 버퍼 히트율을 확인할 수 있으며, DB 왕복이 제거되어 응답 시간이 마이크로초 단위로 떨어집니다. 단, 버퍼링된 뷰는 일부 SQL 기능(서브쿼리, 집계, 일부 조인)에서 제약이 있고, 변경 후 동기화에 약간의 지연이 발생할 수 있다는 점을 고려해야 합니다.
힌트 2 — %_HINTS HANA로 옵티마이저에 직접 지시
두 번째는 ABAP SQL 안에서 HANA에게 직접 힌트를 전달하는 방법입니다. 실행 계획이 통계 변화에 따라 흔들리는 병목 쿼리, 또는 야간 배치처럼 특정 인덱스를 반드시 타야 안정적인 쿼리에 유효합니다.
DATA: lv_bukrs TYPE bukrs VALUE '1000'.
SELECT FROM zi_sales_order
FIELDS so_id, net_amount, currency_code
WHERE company_code = @lv_bukrs
AND order_date >= @lv_from_date
ORDER BY so_id
%_HINTS HANA 'INDEX_ACCESS("VBAK" "VBAK~0")'
INTO TABLE @DATA(lt_orders).
위 예제는 VBAK 테이블의 기본 인덱스(VBAK~0)를 강제로 사용하도록 지시합니다. 그 외 자주 쓰이는 힌트로는 다음이 있습니다.
NO_INDEX— 인덱스 사용 억제, 풀스캔 강제USE_HEX_PLAN— HEX(HANA SQL Execution) 엔진 강제NO_USE_HEX_PLAN— HEX 비활성화, OpenSQL 엔진 사용RESULT_LAG('hana_sr', 0)— 시스템 복제 환경에서 일관성 제어NO_CALC_VIEW_UNFOLDING— Calculation View 언폴딩 억제
힌트는 "고정 핀"입니다. 데이터 양과 분포가 바뀌면 부적절해질 수 있으므로, 적용 시 반드시 코멘트로 적용 근거와 PlanViz 측정값을 남기는 것이 권장됩니다.
힌트 3 — @ObjectModel.usageType으로 뷰의 의도 선언
세 번째는 어노테이션을 통해 뷰의 사용 의도와 규모를 선언하는 방식입니다. 옵티마이저뿐 아니라 RAP 프레임워크, Fiori Elements 런타임, Analytical Engine까지 이 정보를 참고합니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Header — Analytical'
@ObjectModel.usageType: {
serviceQuality: #X,
sizeCategory: #M,
dataClass: #MIXED
}
@VDM.viewType: #BASIC
define view entity ZI_SalesOrder
as select from vbak
{
key vbeln as SalesOrder,
audat as OrderDate,
vkorg as SalesOrg,
netwr as NetAmount,
waerk as Currency
}
주요 속성 의미는 다음과 같습니다.
- serviceQuality:
#A(분석),#T(트랜잭션),#B(기본),#D(파생),#X(미분류). 뷰가 어떤 워크로드에 쓰일지 알려줍니다. - sizeCategory:
#S(천 건 이하)부터#XXL(억 건 이상)까지 예상 레코드 규모 - dataClass:
#MASTER,#TRANSACTIONAL,#ORGANIZATIONAL,#CUSTOMIZING,#MIXED등 데이터의 성격
예를 들어 sizeCategory: #XL로 선언된 뷰는 옵티마이저가 처음부터 해시 조인이나 병렬 처리 전략을 우선 고려하고, RAP 런타임은 페이징·서버사이드 정렬을 더 적극적으로 적용합니다. 반대로 #S로 선언된 마스터 뷰는 네스티드 루프 조인이 선호될 수 있습니다.
세 힌트의 조합 전략 — 워크로드별 패턴
실무에서는 단일 힌트보다 조합이 효과적입니다. 흔히 쓰이는 패턴은 다음과 같습니다.
- 마스터 데이터 뷰:
buffering: #SINGLE+serviceQuality: #B+dataClass: #MASTER+sizeCategory: #S - 트랜잭션 헤더 뷰:
serviceQuality: #T+dataClass: #TRANSACTIONAL+ 필요 시%_HINTS HANA 'INDEX_ACCESS(...)' - 분석용 큐브 뷰:
serviceQuality: #A+sizeCategory: #XL+@Analytics.dataCategory: #CUBE - 혼합 워크로드 뷰:
dataClass: #MIXED+ 클라이언트 쿼리에서 상황별%_HINTS
특히 분석용 뷰에 대해 트랜잭션 화면에서 단건 조회가 일어나는 경우, 옵티마이저가 분석 전략(해시 조인, 컬럼 스토어 풀스캔)을 선택해 오히려 느려지는 일이 발생합니다. 이때 호출부에서 %_HINTS HANA 'NO_USE_HEX_PLAN'이나 인덱스 접근 힌트로 보정하는 패턴이 유효합니다.
흔한 실수와 대응
실수 1 — 버퍼링 가능 여부 미검토. 버퍼링은 모든 SQL 기능과 호환되지 않습니다. JOIN, 집계 함수, 일부 서브쿼리가 포함된 뷰에 버퍼링을 켜면 활성화가 되지 않거나 런타임에 우회됩니다. 활성화 직후 ST10에서 버퍼 상태를 확인하는 것이 권장됩니다.
실수 2 — %_HINTS의 호환성 문제. ABAP Cloud(Steampunk)나 Released CDS 위에서 직접 SELECT 할 때, %_HINTS HANA는 DB 종속이라 클라우드 화이트리스트에 막힐 수 있습니다. 이 경우 CDS 뷰 정의 안의 @Hints 어노테이션이나 hint table 함수를 검토하는 편이 안전합니다.
실수 3 — usageType 잘못 선언. sizeCategory: #S로 잘못 선언된 대용량 뷰는 옵티마이저가 잘못된 조인 전략을 선택해 메모리 폭증을 일으킬 수 있습니다. 통계 기반으로 실제 레코드 수를 확인한 뒤 선언하는 습관이 필요합니다.
FAQ.
- 버퍼링과 HANA 컬럼 스토어 캐시는 다른가? 다릅니다. 버퍼링은 ABAP 애플리케이션 서버 메모리에 저장되어 DB 자체를 호출하지 않습니다. 컬럼 스토어 캐시는 HANA 내부 캐시로, 여전히 DB 왕복은 발생합니다.
- %_HINTS는 모든 DB에서 동작하나?
%_HINTS HANA는 HANA에서만 적용되며 다른 DB에서는 무시됩니다. 멀티 DB 지원이 필요하면 DB별로 별도 힌트를 명시할 수 있습니다. - RAP BO에서 힌트는 어디에 두나? 일반적으로 Interface View 레벨에 usageType과 buffering을, Behavior 구현부의 ABAP SQL에
%_HINTS를 두는 분리 패턴이 권장됩니다.
다음으로 살펴볼 주제
성능 힌트 다음 단계로는 다음 주제를 권장합니다.
- HANA PlanViz를 활용한 실행 계획 분석과 힌트 효과 측정
- CDS Table Function으로 AMDP 호출, 복잡 로직의 DB 푸시다운
@Analytics어노테이션과 Analytical Engine 최적화- RAP의 Strict Mode와 Released CDS API 관리
- ABAP SQL의
FOR ALL ENTRIES대체 패턴(Path Expression, Join)
힌트는 만능이 아닙니다. 인덱스 설계, 통계 갱신, 모델 단순화 같은 기본기가 우선이며, 힌트는 그 위에서 마지막 1~2단계의 추가 최적화를 끌어내는 도구로 활용하는 것이 일반적입니다.
댓글 0
아직 댓글이 없습니다.