ABAP SQL 튜닝 ② - 결과 집합을 줄여라

ABAP SQL 튜닝 2편 배너

ABAP SQL 튜닝 시리즈 두 번째 글입니다.

가장 흔한 실수 - ABAP에서 거르기

성능 리뷰를 하다 보면 반복해서 만나는 패턴입니다.

!나쁜 방식다 가져와서 ABAP에서 버린다

DB는 전건을 읽어 네트워크로 전부 보내고, ABAP은 그중 대부분을 버립니다. 양쪽 다 낭비입니다.

좋은 방식DB에서 걸러서 받는다

조건을 WHERE절로 내려보냅니다. DB가 인덱스로 필요한 행만 찾아 돌려줍니다.

1" ✗ 나쁨 - 전건을 가져와 ABAP에서 거른다
2SELECT * FROM zsales INTO TABLE @DATA(lt_all).
3LOOP AT lt_all INTO DATA(ls_row).
4  CHECK ls_row-werks = '1000'.      " 여기서 99%를 버린다
5  ...
6ENDLOOP.
7
8" ✗ 이것도 같은 문제 - 가져온 뒤 지운다
9SELECT * FROM zsales INTO TABLE @lt_all.
10DELETE lt_all WHERE werks <> '1000'.
11
12" ✓ 좋음 - DB에서 거른다
13SELECT * FROM zsales
14  WHERE werks = @lv_werks
15  INTO TABLE @DATA(lt_target).

CHECKDELETE ... WHERE 로 내부 테이블을 거르는 코드가 보이면, 그 조건이 왜 WHERE절에 없는지 먼저 의심하세요. 대부분은 그냥 옮기면 됩니다.

인덱스는 언제 동작하나

WHERE절을 썼다고 항상 빨라지는 건 아닙니다. DB가 인덱스를 탈 수 있어야 합니다.

인덱스는 여러 필드를 정해진 순서로 묶어놓은 목록입니다. 전화번호부가 "성 → 이름" 순으로 정렬된 것과 같습니다.

인덱스를 탄다앞쪽 필드부터 조건을 준다

인덱스가 (MANDT, BUKRS, GJAHR) 순이라면, 앞에서부터 연속으로 조건을 주어야 효율이 납니다.

!못 탄다앞 필드를 건너뛴다

BUKRS 없이 GJAHR만 주면, 전화번호부에서 성을 모른 채 이름만으로 찾는 것과 같습니다.

인덱스를 무력화하는 패턴

1" ✗ 앞에 와일드카드 - 인덱스 탐색이 어렵다
2SELECT * FROM zsales WHERE matnr LIKE '%-001' INTO TABLE @lt.
3
4" ✗ 부정 조건 - 대부분의 행이 대상이라 인덱스 의미가 없다
5SELECT * FROM zsales WHERE werks <> '1000' INTO TABLE @lt.
6
7" ✗ 조건이 사실상 없음 - 전건 조회
8SELECT * FROM zsales INTO TABLE @lt.

특히 LIKE '%...' 처럼 앞이 열린 패턴은 인덱스를 앞에서부터 훑을 수 없어 효율이 급격히 떨어집니다.

TIP

조건을 짤 때 스스로에게 물어보세요. "이 조건으로 전체의 몇 %가 남는가?" 90%가 남는 조건이라면 인덱스는 도움이 안 됩니다. 선택도가 높은(적게 남는) 조건이 앞에 있어야 합니다.

실행 계획으로 확인하기

인덱스를 타는지 추측하지 말고 확인하세요. ST05에서 해당 SQL을 잡은 뒤 실행 계획(Explain) 을 보면, DB가 어떤 경로로 데이터를 찾았는지 나옵니다.

여기서 전체 스캔이 보이는데 결과 건수가 적다면, 조건이나 인덱스에 문제가 있다는 신호입니다.

S/4HANA에서의 인덱스

전통적인 디스크 기반 DB 시절의 습관을 그대로 가져오면 안 되는 영역입니다.

기존 DB보조 인덱스를 적극 추가

느린 쿼리가 있으면 인덱스를 만들어 해결하는 접근이 일반적이었습니다.

HANA먼저 쿼리를 고친다

컬럼 스토어 구조상 인덱스 없이도 처리되는 경우가 많고, 인덱스는 메모리와 쓰기 비용을 유발합니다. 남발할 대상이 아닙니다.

WARNING

그렇다고 "HANA에는 인덱스가 필요 없다"는 말은 과장입니다. 대용량 테이블에서 선택도 높은 조건으로 소량을 뽑는 패턴에는 여전히 도움이 됩니다. 다만 인덱스 추가는 마지막 수단이고, 그 전에 쿼리와 조건을 먼저 손봐야 합니다. 추가 여부는 Basis·DBA와 협의하세요.

필요한 만큼만 가져오기

행 수를 줄이는 다른 방법도 있습니다.

1" 1건만 필요하면 SELECT SINGLE (전체 키 지정이 원칙)
2SELECT SINGLE * FROM zsales
3  WHERE mandt = @sy-mandt AND vbeln = @lv_vbeln
4  INTO @DATA(ls_row).
5
6" 상위 N건만 필요하면 UP TO n ROWS + ORDER BY
7SELECT * FROM zsales
8  WHERE werks = @lv_werks
9  ORDER BY erdat DESCENDING
10  INTO TABLE @DATA(lt_recent)
11  UP TO 10 ROWS.
12
13" 존재 여부만 확인하면 되면 굳이 데이터를 안 가져와도 된다
14SELECT SINGLE @abap_true FROM zsales
15  WHERE werks = @lv_werks
16  INTO @DATA(lv_exists).
INFO

SELECT SINGLE전체 키를 지정했을 때 1건이 보장됩니다. 키 일부만 주면 "조건에 맞는 것 중 아무거나 1건"이 오므로, 어떤 행이 올지 정해지지 않습니다. 정렬 기준이 필요하면 ORDER BY ... UP TO 1 ROWS를 쓰세요.

정리

  • DB에서 거를 수 있는 것은 DB에서 거른다. CHECK·DELETE로 내부 테이블을 정리하는 코드는 대부분 WHERE절로 옮길 수 있습니다.
  • 인덱스는 앞 필드부터 연속으로 조건을 줄 때 잘 동작합니다.
  • 선택도를 먼저 생각하세요. 많이 남는 조건은 인덱스가 있어도 소용없습니다.
  • 추측하지 말고 실행 계획으로 확인하세요.
  • HANA에서 인덱스 추가는 마지막 수단입니다.

다음 ③편에서는 행이 아니라 , 즉 전송량 줄이기를 다룹니다.

Disclaimer — 이 포스트는 AI(Claude)를 활용하여 작성된 초안을 바탕으로 검수 및 보완하여 작성되었습니다. 내용 중 오류나 오타가 있다면 댓글로 알려주시면 감사하겠습니다.