ABAP 리포트 프로그램이 대량 데이터를 처리할 때 사용자가 가장 답답해 하는 게 "이거 도대체 얼마나 더 걸리는 거지?" 입니다. 화면이 멈춰 보이면 사용자는 프로그램이 죽은 줄 알고 강제 종료하기 십상이죠. 이 상황을 해결하는 가장 단순한 UX 개선이 프로그레스 바(진행률 표시) 입니다.
SAP는 두 가지 표준 방식을 제공합니다. 오래된 펑션 모듈 SAPGUI_PROGRESS_INDICATOR 와 현대적 클래스 cl_akb_progress_indicator. 둘 다 SAP GUI 좌측 하단에 진행 상태를 노란색 바와 메시지로 표시해 줍니다.
이 글은 펑션 방식·클래스 방식 + 성능 최적화 트릭(같은 % 일 때 호출 생략) 을 정리한 메모입니다.
핵심 원리
두 방식의 동작 차이를 정리합니다.
| 방식 | 호출 형태 | 언제 쓰는가 |
|---|---|---|
| 펑션 방식 | CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR' |
레거시 코드와 통합 / FORM 으로 래핑해 재사용 |
| 클래스 방식 | cl_akb_progress_indicator=>get_instance( ) |
신규 개발 / 깔끔한 OOP 패턴 선호 |
둘 다 SAP GUI 좌측 하단 상태바에 노란 진행 바와 텍스트를 띄워줍니다. 사용자 입장에서는 동일한 경험이지만, 코드 측면에서는 클래스 방식이 더 간결합니다.
핵심 성능 포인트는 공통입니다 — 퍼센트가 바뀔 때만 호출 해야 한다는 점. 매 LOOP 마다 호출하면 화면 갱신 오버헤드 때문에 처리 속도가 크게 떨어집니다.
1단계 — 대상 데이터 조회 + 라인 수 확보
진행률 계산에는 현재 위치(sy-tabix) 와 전체 라인 수 두 값이 필요합니다. LOOP 시작 전에 전체 라인 수를 미리 잡아두는 게 중요.
DATA: mara_lines TYPE i, " 전체 라인 수
gd_percent TYPE i. " 직전 표시된 퍼센트 (중복 호출 방지용)
START-OF-SELECTION.
SELECT *
INTO TABLE @DATA(gt_data)
FROM mara.
" 전체 라인 수 확보
DESCRIBE TABLE gt_data LINES mara_lines.
CLEAR gd_percent.
LOOP AT gt_data INTO DATA(gs_data).
PERFORM progress_bar USING 'reading internal table data...'
sy-tabix
mara_lines.
" 실제 처리 로직 ...
ENDLOOP.
핵심 포인트:
DESCRIBE TABLE ... LINES로 전체 라인 수 조회 (sy-dbcnt도 가능)gd_percent— 직전 호출 시 퍼센트 저장. 다음 LOOP 에서 같은 % 면 호출 생략하는 가드 변수- 매 LOOP 마다
progress_barFORM 에 현재 위치·전체 라인 수 전달
2단계 — 펑션 방식 FORM 작성
재사용 가능한 progress_bar FORM 을 만듭니다. 안에서 SAPGUI_PROGRESS_INDICATOR 펑션을 호출하는 구조.
FORM progress_bar USING p_value " 표시할 메시지
p_tabix " 현재 위치
p_nlines. " 전체 라인 수
DATA: w_percentage TYPE p,
w_percent_char(3).
" 1) 퍼센트 계산
w_percentage = ( p_tabix / p_nlines ) * 100.
w_percent_char = w_percentage.
" 2) 앞 공백 제거 (왼쪽 정렬용)
SHIFT w_percent_char LEFT DELETING LEADING ' '.
" 3) 표시 메시지 조립 — "메시지 76 %"
DATA(w_text2) = |{ p_value } { w_percent_char } %|.
" ★ 핵심: 퍼센트가 바뀌었을 때만 호출 (성능 최적화)
IF w_percentage GT gd_percent OR p_tabix EQ 1.
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = w_percentage
text = w_text2.
gd_percent = w_percentage.
ENDIF.
ENDFORM.
핵심 포인트:
w_percentage TYPE p— Packed 타입으로 소수점 없는 정수 % 계산SHIFT LEFT DELETING LEADING— 숫자 변환 시 생기는 앞 공백 제거 (" 76" → "76")IF w_percentage GT gd_percent— 핵심 성능 트릭. 직전 % 보다 클 때만 호출 → 같은 % 일 때 펑션 호출 절약OR p_tabix EQ 1— 첫 라인일 때는 무조건 한 번 표시해서 사용자에게 "시작됐다" 신호
3단계 — 성능 최적화의 중요성
100만 건 LOOP 에서 진행 바를 매번 호출하면 어떤 일이 일어날까요?
| 호출 빈도 | 결과 |
|---|---|
| 매 LOOP 마다 호출 (1,000,000회) | 화면 갱신 오버헤드로 처리 시간 급증 — 진행 바가 오히려 발목 잡음 |
| % 변경 시에만 호출 (최대 100회) | 화면 갱신 부담 거의 없음. 진짜 처리 속도 그대로 유지 |
100% 까지 가는 동안 진행 바 갱신은 최대 100번 이면 충분합니다(1%, 2%, … 100%). 매 LOOP 가 아니라 퍼센트가 정수 단위로 바뀔 때만 호출하도록 가드를 두는 게 핵심 트릭. 위 FORM 의 IF w_percentage GT gd_percent 가 정확히 그 역할입니다.
4단계 — 클래스 방식 대안
신규 개발이면 좀 더 깔끔한 클래스 방식을 권장합니다. 별도 FORM 정의 없이도 인스턴스만 만들면 끝.
CONSTANTS: co_max TYPE i VALUE 1000000.
START-OF-SELECTION.
" 1) 싱글톤 인스턴스 획득
DATA(o_progress) = cl_akb_progress_indicator=>get_instance( ).
DO co_max TIMES.
" 2) 매 LOOP 호출해도 내부적으로 % 단위 최적화됨
o_progress->display(
force_display = abap_false " false = 변경 시에만 실제 표시
total = co_max " 전체 건수
processed = sy-index " 현재 위치
message = 'test progress' ).
ENDDO.

핵심 포인트:
get_instance( )— 싱글톤 패턴. 매번 새 객체 생성하지 않음force_display = abap_false— 클래스 내부에서 알아서 % 단위 최적화 처리. 펑션 방식처럼 직전 % 비교 가드를 따로 만들 필요 없음total·processed가 전체/현재 위치. % 는 클래스가 자동 계산
펑션 방식보다 코드가 짧고, % 비교 가드 로직이 클래스 내부로 캡슐화 되어 있어 실수할 여지가 적습니다.
흔히 빠뜨리는 함정
매 LOOP 마다 호출 (성능 가드 누락)
가장 흔한 함정. 펑션 방식에서 IF w_percentage GT gd_percent 가드 없이 매번 CALL FUNCTION 하면 100만 건 처리에 30분 걸릴 게 2~3시간으로 늘어남. 반드시 가드 또는 클래스 방식의 force_display = abap_false 사용.
0으로 나누기
p_nlines 가 0인 상태로 p_tabix / p_nlines 계산하면 즉시 덤프(COMPUTE_BCD_OVERFLOW). 빈 테이블 LOOP 는 안 들어가지만, 호출 전에 라인 수 0 체크 권장.
전체 라인 수 안 채움
DESCRIBE TABLE ... LINES 호출을 빼먹고 0으로 두면 진행 바가 항상 0%로 표시되거나 위 0 나누기 발생. SELECT 직후 반드시 라인 수 확보.
첫 라인 표시 누락
IF w_percentage GT gd_percent 조건만 두면 처음 1% 가 되기 전까지는 화면에 아무것도 안 뜨다가 갑자기 1%부터 나타남. OR p_tabix EQ 1 추가해서 첫 라인에 무조건 한 번 표시.
백그라운드 잡에서 호출 — 의미 없음
진행 바는 SAP GUI(클라이언트) 가 있을 때만 시각적으로 표시. SM37 배치 잡에서는 호출해도 화면에 아무것도 안 뜸. 배치는 SM50 워크프로세스 또는 잡 로그로 진행 상태 확인.
텍스트 길이 제한
SAPGUI_PROGRESS_INDICATOR 의 text 파라미터는 70자 제한. 메시지가 길면 잘림. 자재명·고객명 같은 긴 텍스트는 줄여서 표시.
% 가 100을 넘는 경우
sy-tabix 보정 없이 LOOP 가 끝나도 100% 미만으로 끝나거나 반대로 100을 초과하는 케이스 발생 가능. 마지막에 percentage = 100 명시 호출로 마무리 권장.
전체 코드 — 복사용 통합본
위 단계를 펑션 방식과 클래스 방식 두 가지로 SE38 즉시 실행 가능한 통합본입니다.
펑션 방식 (FORM 래핑)
REPORT zexample_progress_bar_form.
DATA: mara_lines TYPE i,
gd_percent TYPE i.
START-OF-SELECTION.
* 1) 대상 데이터 조회 + 라인 수 확보 ----------------------------------
SELECT *
INTO TABLE @DATA(gt_data)
FROM mara.
DESCRIBE TABLE gt_data LINES mara_lines.
IF mara_lines = 0.
MESSAGE '처리할 데이터가 없습니다.' TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
CLEAR gd_percent.
* 2) LOOP 안에서 progress_bar FORM 호출 ------------------------------
LOOP AT gt_data INTO DATA(gs_data).
PERFORM progress_bar USING 'reading internal table data...'
sy-tabix
mara_lines.
" 실제 처리 로직 ...
ENDLOOP.
* 3) 마지막 100% 명시 마무리 -----------------------------------------
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = 100
text = 'completed'.
*&---------------------------------------------------------------------*
*& Form PROGRESS_BAR
*&---------------------------------------------------------------------*
FORM progress_bar USING p_value " 표시 메시지
p_tabix " 현재 위치
p_nlines. " 전체 라인 수
DATA: w_percentage TYPE p,
w_percent_char(3).
" 퍼센트 계산
w_percentage = ( p_tabix / p_nlines ) * 100.
w_percent_char = w_percentage.
SHIFT w_percent_char LEFT DELETING LEADING ' '.
DATA(w_text2) = |{ p_value } { w_percent_char } %|.
" ★ 핵심: 퍼센트 변경 시에만 호출 (성능 최적화)
IF w_percentage GT gd_percent OR p_tabix EQ 1.
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = w_percentage
text = w_text2.
gd_percent = w_percentage.
ENDIF.
ENDFORM.
클래스 방식 (더 간결)
REPORT zexample_progress_bar_class.
CONSTANTS: co_max TYPE i VALUE 1000000.
START-OF-SELECTION.
* 1) 싱글톤 인스턴스 획득 --------------------------------------------
DATA(o_progress) = cl_akb_progress_indicator=>get_instance( ).
* 2) LOOP 안에서 display 호출 ----------------------------------------
DO co_max TIMES.
" ★ 핵심: force_display = abap_false 면 클래스가 % 단위 최적화
o_progress->display(
force_display = abap_false
total = co_max
processed = sy-index
message = 'test progress' ).
" 실제 처리 로직 ...
ENDDO.
* ※ 클래스 방식은 별도 가드 변수·FORM 정의 불필요
* - get_instance( ) 한 번
* - display( total, processed ) 호출만으로 끝
* - 신규 개발에 우선 권장
요약
| 단계 | 처리 | 핵심 |
|---|---|---|
| 1 | 전체 라인 수 확보 | DESCRIBE TABLE ... LINES |
| 2 | 펑션 방식 — SAPGUI_PROGRESS_INDICATOR | FORM 래핑 + 가드 변수 + percentage/text |
| 3 | 성능 최적화 가드 | IF w_percentage GT gd_percent OR p_tabix EQ 1 |
| 4 | 클래스 방식 — cl_akb_progress_indicator | get_instance( ) + display( total, processed ) |
| 5 | 마무리 | 마지막에 percentage = 100 + 'completed' 명시 호출 |
프로그레스 바 자체는 한 줄짜리 펑션 호출이지만, 퍼센트 변경 시에만 호출 이라는 작은 가드 하나가 성능에 큰 영향을 줍니다. 펑션 방식은 FORM 래핑으로 재사용하고, 신규 개발은 cl_akb_progress_indicator 로 가는 게 깔끔합니다. 사용자에게 "이 프로그램이 살아 있다"는 신호 하나를 주는 것만으로 강제 종료 클레임이 크게 줄어듭니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다. SAPGUI_PROGRESS_INDICATOR 펑션과 cl_akb_progress_indicator 클래스는 SAP GUI 클라이언트 환경에서만 시각적으로 표시되며, 배치 잡(SM37) 에서는 동작하지 않습니다. SAP 버전·GUI 버전에 따라 클래스 가용성이 다를 수 있으므로 운영 환경 적용 전 개발 시스템에서 확인하시기 바랍니다.