본문 바로가기

카테고리 없음

SAP BW 개념 정리

** Claude로 작성됨

SAP BW란?

SAP가 만든 엔터프라이즈 데이터 웨어하우스(EDW) 플랫폼입니다.

ERP(SAP ECC/S4HANA) 등 다양한 소스에서 데이터를 추출·변환·적재(ETL)하여 분석/리포팅에 활용합니다.


데이터 레이어 구조

Source Systems → PSA → DSO(ODS) → InfoCube/ADSO → BEx/BO 리포트
                 ↑                  ↑
              (Staging)          (Data Marts)

 

Staging PSA (Persistent Staging Area) 원천 데이터 원본 보관 - 가공 전 대기장소
Integration DSO / ADSO 세부 트랜잭션 데이터 저장의 개념 (일반 원장 / 스타 스키마)
Reporting InfoCube / ADSO 집계/분석용 멀티차원 모델

핵심 객체

  • DataSource : 소스시스템 추출 정의 (일반적인 ETL툴의 커넥터 개념 + 데이터 별 처리 방식 정의)
  • InfoObject : 가장 기본 단위 (차원 - 텍스트 컬럼 정의/키피겨 - 숫자 컬럼 정의) - 컬럼의 스키마
  • DSO (Data Store Object) : 행 기반 상세 데이터
  • InfoCube : 스타스키마 기반 OLAP 큐브
  • ADSO (Advanced DSO) : BW/4HANA에서 DSO+InfoCube 통합한 차세대 객체
  • Transformation / DTP : ETL 변환 및 적재 규칙 (변환 규칙 : 컬럼의 변환, 값의 치환, 고급 ABAP 쿼리 적용 등)
    DTP(Data Transfer Process)에서 full load(전체 적재), Delta load(증분 적재)의 개념이 정의되고 실행 조정됨
  • Process Chain : Airflow DAG과 같은 개념의 워크플로우

ETL 흐름 (데이터 엔지니어 핵심)

ERP 시스템
    ↓  (DataSource가 정의한 방식으로 추출)
PSA  ← 원본 데이터 그대로 보관, 에러 확인 가능
    ↓  (Transformation 규칙 적용)
DSO/ADSO  ← 정제된 상세 데이터 저장 (트랜잭션 레벨)
    ↓  (Transformation 규칙 적용)
InfoCube/ADSO  ← 분석용 집계 데이터
    ↓
BEx/BO/SAC  ← 리포트, 대시보드

※ 위의 각 화살표 = DTP 실행
※ 전체 흐름 자동화 = Process Chain

 

데이터 엔지니어 관점 준비사항

소스 연결 정의 DataSource 생성/설정
테이블/모델 설계 InfoObject, ADSO 설계
ETL 로직 작성 Transformation Rule (*ABAP Routine : 아래 별도 설명 추가)
파이프라인 실행 DTP 실행 (**Delta 적재 설명 아래 별도 설명)
스케줄링/자동화 Process Chain 설계 (각 단계 작업별 퍼포먼스 튜닝 노하우 필요)
모니터링 RSA1(BW Admin), SM37(Job 모니터), ST22(덤프) 트랜잭션 코드 사용

3. 외부 연동 시 고려사항 (BW를 전사 데이터 플랫폼으로 사용중인 경우)

  • BW → 외부 시스템 : Open ODS View, ODP(Operational Data Provisioning)
  • 외부 → BW 적재 : BAPI, File Interface, DB Connect
  • 클라우드 연동 : SAP BW Bridge (BW/4HANA ↔ Datasphere)

2026년 최근 트렌드

장기적으로 SAP Datasphere(구 SAP DW Cloud)로 전환을 유도 중, BW/4HANA와 Datasphere 간 브리지 연동 파악 필요

 


* 델타 적재  

3가지 초기화 단계

[1단계] Init (초기화)          [2단계] Delta (증분)        [3단계] Full (필요시)
처음 한 번만 실행               이후 매번 실행               전체 재적재 필요할 때
전체 데이터 가져오기 +          마지막 Init/Delta 이후        Delta 포인터 무시하고
"여기까지 가져왔다" 표시         변경분만 가져오기              전체 다시 가져옴

⚠️ 중요: Init을 실행해야 Delta 포인터가 생성됩니다. Init 없이 Delta 실행하면 에러


델타 방식의 종류 (핵심)

SAP BW에서 델타를 감지하는 방식이 여러 가지입니다.

① After Image (AI) — 가장 일반적

변경 전: 고객A 매출 = 1000
변경 후: 고객A 매출 = 1500

Delta로 오는 것: 1500 (최종값 전체)
→ BW에서 기존 값을 덮어씀(Overwrite)

 

② Before Image + After Image (AIE) — 수정/삭제 추적

변경 전 레코드: 고객A 매출 1000  (Before Image, 부호 반전해서 -1000으로 전송)
변경 후 레코드: 고객A 매출 1500  (After Image, +1500으로 전송)

BW에서 합산: -1000 + 1500 = +500 반영
→ 수정/취소 트랜잭션 처리에 사용

 

③ Additive Delta — 누적 합산

월요일 Delta: 판매량 +100
화요일 Delta: 판매량 +50
수요일 Delta: 판매량 +30

BW에서 합산: 100 + 50 + 30 = 180
→ 증가분을 계속 더함 (판매 실적, 로그성 데이터)

 

④ Timestamp 기반 — 시간으로 변경 감지

%sql
-- 소스 테이블에 변경일시 컬럼이 있을 때
SELECT * FROM SALES_TABLE
WHERE LAST_CHANGED_AT > '마지막_Delta_실행_시각'

 

⑤ Change Log / Change Pointer — SAP 내부 방식

SAP ERP가 데이터 변경될 때마다
→ 변경 내역을 Change Log 테이블에 자동 기록
→ BW가 이 Log 테이블을 읽어서 Delta 처리

(SAP끼리 연결할 때 가장 안정적인 방법)

Delta 포인터

타임라인:
─────────────────────────────────────────────→ 시간
     [Init 실행]    [Delta #1]    [Delta #2]
          ↑              ↑             ↑
     전체 복사      여기까지 표시   여기까지 표시
                   "포인터 이동"   "포인터 이동"

Delta 포인터 = "어디까지 가져왔는지 기억하는 책갈피"

⚠️ Delta 포인터는 DTP 성공 시에만 이동합니다. 실패하면 포인터가 그대로 → 다음 Delta 실행 시 실패 구간부터 다시 시도


실무에서 자주 겪는 Delta 문제

문제 상황원인해결 방법
Delta인데 데이터가 안 옴 Init 안 했거나 포인터 손상 Init 재실행
데이터 중복 적재 Delta 실패 후 재실행 시 중복 DSO의 Key 기반 Overwrite 확인
Delta 누락 소스에서 Change Log 삭제됨 Full Load 후 Init 재설정
시간 지연 소스 시스템 Timestamp 지연 Safety Interval 설정 (통상 30분~1시간)

** ABAP Routine

ABAP의 개념

ABAP(Advanced Business Application Programming) 은 SAP가 만든 자체 프로그래밍 언어

Transformation 안의 Routine 종류

┌─────────────────────────────────────────────────┐
│              Transformation                     │
│                                                 │
│  [Start Routine]  → 전체 패키지 단위 전처리           │
│       ↓                                         │
│  [Field Routine]  → 특정 필드 하나씩 변환            │
│       ↓                                         │
│  [End Routine]    → 전체 패키지 단위 후처리           │
│       ↓                                         │
│  [Expert Routine] → 위 3개를 모두 직접 제어          │
└─────────────────────────────────────────────────┘

Start Routine — "들어오는 데이터 묶음을 통째로 전처리"

%abap
" 전체 소스 데이터 패키지가 내부 테이블로 들어옴
" RESULT_PACKAGE = 소스에서 온 데이터 전체 묶음

START-OF-ROUTINE.

  " 예시: 소스 데이터 중 취소 건(CANCEL_FLAG = 'X')은 아예 제거
  DELETE RESULT_PACKAGE WHERE CANCEL_FLAG = 'X'.

  " 예시: 특정 날짜 이전 데이터 제거
  DELETE RESULT_PACKAGE WHERE POSTING_DATE < '20200101'.

END-OF-ROUTINE.

💡 언제 쓰나?

  • 특정 조건의 레코드를 통째로 필터링할 때
  • 소스 데이터를 일괄 전처리 해야 할 때
  • 외부 테이블 한 번만 조회해서 전체에 활용할 때 (성능상 유리)

Field Routine — "필드 하나의 변환 로직"

%abap
" RESULT = 목적지 필드에 넣을 값
" SOURCE_FIELDS = 소스의 모든 필드

" ── 예시 1: 단순 매핑 ──────────────────────────
RESULT = SOURCE_FIELDS-CUSTOMER_ID.


" ── 예시 2: 조건부 변환 ─────────────────────────
IF SOURCE_FIELDS-SALES_REGION = 'KR'.
  RESULT = '한국'.
ELSEIF SOURCE_FIELDS-SALES_REGION = 'US'.
  RESULT = '미국'.
ELSE.
  RESULT = '기타'.
ENDIF.


" ── 예시 3: 날짜 포맷 변환 ──────────────────────
" 소스: 'DD.MM.YYYY' → BW: 'YYYYMMDD'
DATA: LV_DATE TYPE CHAR10.
LV_DATE = SOURCE_FIELDS-POSTING_DATE.   " '15.06.2024'
RESULT+0(4) = LV_DATE+6(4).             " YYYY
RESULT+4(2) = LV_DATE+3(2).             " MM
RESULT+6(2) = LV_DATE+0(2).             " DD
" 결과: '20240615'


" ── 예시 4: NULL 처리 ───────────────────────────
IF SOURCE_FIELDS-AMOUNT IS INITIAL.
  RESULT = 0.
ELSE.
  RESULT = SOURCE_FIELDS-AMOUNT.
ENDIF.

End Routine — "적재 직전 최종 가공"

%abap
" RESULT_PACKAGE = 변환이 다 끝난 데이터 묶음
" 여기서 최종 조정 가능

END-OF-ROUTINE.

  " 예시: 중복 제거 (같은 KEY를 가진 레코드)
  SORT RESULT_PACKAGE BY CUSTOMER_ID PRODUCT_ID POSTING_DATE.
  DELETE ADJACENT DUPLICATES FROM RESULT_PACKAGE
    COMPARING CUSTOMER_ID PRODUCT_ID POSTING_DATE.

  " 예시: 금액 합산 후 특정 임계값 이하 제거
  DELETE RESULT_PACKAGE WHERE SALES_AMOUNT < 1000.

END-OF-ROUTINE.

실무에서 자주 쓰는 ABAP 패턴

패턴 1 — 다른 테이블 값 조회 (Lookup)

%abap
" 고객번호로 고객 등급을 별도 테이블에서 가져오는 경우
DATA: LV_GRADE TYPE CHAR2.

SELECT SINGLE CUST_GRADE
  INTO LV_GRADE
  FROM ZCUST_MASTER          " Z로 시작 = 커스텀 테이블
  WHERE CUSTOMER_ID = SOURCE_FIELDS-CUSTOMER_ID.

IF SY-SUBRC = 0.             " SY-SUBRC: 조회 성공 여부 (0 = 성공)
  RESULT = LV_GRADE.
ELSE.
  RESULT = '미분류'.
ENDIF.

⚠️ 주의: Field Routine 안에서 DB 조회는 레코드 건수만큼 반복 실행됨 → 데이터가 많으면 Start Routine에서 한 번에 조회 후 내부 테이블로 캐싱 권장


패턴 2 — Start Routine에서 캐싱 (성능 최적화)

%abap
" Start Routine에서 마스터 테이블 전체를 한 번만 읽어서 캐싱
DATA: GT_CUST_MASTER TYPE TABLE OF ZCUST_MASTER.  " 내부 테이블 선언

SELECT CUSTOMER_ID CUST_GRADE CUST_NAME
  INTO TABLE GT_CUST_MASTER
  FROM ZCUST_MASTER.

" 이후 Field Routine에서 GT_CUST_MASTER를 READ TABLE로 조회
" → DB 반복 조회 없이 메모리에서 빠르게 처리


패턴 3 — 에러 레코드 제거

%abap
" Start Routine에서 필수값 없는 레코드 제거
LOOP AT RESULT_PACKAGE ASSIGNING FIELD-SYMBOL(<LS_ROW>).

  IF <LS_ROW>-CUSTOMER_ID IS INITIAL
  OR <LS_ROW>-POSTING_DATE IS INITIAL.

    DELETE RESULT_PACKAGE.  " 현재 루프 레코드 삭제
  ENDIF.

ENDLOOP.

ABAP 기본 문법 요약 (데이터 엔지니어용)

%abap
" ── 변수 선언 ────────────────────────────────────
DATA: LV_NAME   TYPE CHAR50,      " 문자열 50자
      LV_AMOUNT TYPE P DECIMALS 2, " 소수점 2자리 숫자
      LV_DATE   TYPE DATS,         " 날짜 (YYYYMMDD)
      LV_FLAG   TYPE CHAR1.        " 플래그 (X / 공백)

" ── 조건문 ──────────────────────────────────────
IF LV_FLAG = 'X'.
  " 참일 때
ELSEIF LV_FLAG = ' '.
  " 다른 조건
ELSE.
  " 나머지
ENDIF.

" ── 반복문 ──────────────────────────────────────
LOOP AT RESULT_PACKAGE INTO LS_ROW.
  " 각 행 처리
ENDLOOP.

" ── DB 조회 ─────────────────────────────────────
SELECT SINGLE FIELD1 FIELD2
  INTO (LV_VAR1, LV_VAR2)
  FROM TABLE_NAME
  WHERE KEY_FIELD = LV_KEY.

" ── 문자열 합치기 ────────────────────────────────
CONCATENATE LV_YEAR LV_MONTH LV_DAY INTO LV_DATE.
" 또는 (신문법)
LV_DATE = |{ LV_YEAR }{ LV_MONTH }{ LV_DAY }|.

데이터 엔지니어가 실수하기 쉬운 포인트

실수왜 문제인가올바른 방법
Field Routine에서 매 레코드 SELECT 100만번 DB 조회 → 극심한 성능 저하 Start Routine에서 조회 후 내부 캐싱
SY-SUBRC 확인 안 함 DB 조회 실패해도 모르고 넘어감 SELECT 후 항상 IF SY-SUBRC = 0 체크
RESULT_PACKAGE 직접 수정 중 인덱스 오류 LOOP 중 DELETE 잘못 쓰면 건너뜀 발생 FIELD-SYMBOL 방식 사용 또는 역순 LOOP
날짜 타입 혼용 CHAR vs DATS 타입 다르면 비교 오류 타입 통일 후 비교