ABAP SQL 튜닝 시리즈 다섯 번째 글입니다. 이번 편과 ⑥편은 대량 조회를 다룹니다. 이번은 조회 속도, 다음은 메모리입니다.
수백만 건짜리 테이블을 화면에 뿌릴 수는 없습니다. 한 번에 일부만 잘라서 가져오는 것이 페이징입니다.
방식은 크게 두 가지이고, 성격이 완전히 다릅니다.
가장 직관적인 방식입니다. "처음 100건 건너뛰고 그다음 20건"처럼 지정합니다.
ABAP SQL에서는 OFFSET을 쓸 수 있습니다.
OFFSET은 ABAP 릴리스 7.50 이상에서 사용할 수 있고, ORDER BY가 반드시 있어야 합니다. 정렬 없이 건너뛰는 것은 의미가 없기 때문입니다. 문법 순서와 사용 가능 여부는 실제 시스템에서 확인하세요.
여기가 핵심입니다. OFFSET 100000은 "10만 건을 안 읽는다"는 뜻이 아닙니다.
DB는 조건에 맞는 행을 정렬해서 앞에서부터 세어 나갑니다. 10만 번째부터 주려면 앞의 10만 건을 만들어 버려야 합니다.
1페이지는 빠르고, 5,000페이지는 느립니다. 이걸 deep paging 문제라고 부릅니다.
10건을 받는데 앞의 10만 건을 만들어 버리는 셈이니, 페이지가 깊어질수록 낭비가 커집니다.
또 하나의 문제입니다. 1페이지를 보고 2페이지로 넘어가는 사이에 누군가 데이터를 추가하거나 지우면 경계가 밀립니다.
조회 전용 화면이면 넘어갈 수 있지만, 순차 배치 처리에서 이런 누락이 생기면 사고입니다.
다른 접근입니다. "몇 건 건너뛸지"가 아니라 "어디서부터 이어서 읽을지" 를 지정합니다. 직전 페이지의 마지막 행 키를 조건으로 넘깁니다.
조건이 vbeln > '0000012345' 형태의 범위 조건으로 바뀝니다. 정렬 키에 인덱스가 있다면, DB는 인덱스에서 그 지점을 바로 찾아 거기서부터 20건만 읽으면 됩니다.
건너뛸 행을 만들 필요가 없습니다. 그래서 1페이지든 5,000페이지든 비용이 거의 같습니다.
정렬 키가 유일하지 않으면 문제가 생깁니다. vbeln만으로 정렬했는데 같은 vbeln이 여러 건이면, 경계에서 행이 잘리거나 겹칩니다.
그래서 위 예제처럼 정렬 키를 유일해질 때까지 늘리고, 조건도 그에 맞춰 씁니다.
키가 3개면 조건이 한 단계 더 중첩됩니다. 다소 번거롭지만 이 조건이 정확해야 누락·중복이 안 생깁니다.
정렬 키에 유일성을 보장하는 필드를 마지막에 하나 넣어두면, 조건이 단순해집니다. 대개 기본키의 마지막 필드를 tie-break로 씁니다.
정리하면 페이지 번호를 눌러 이동하는 화면은 OFFSET, 아래로 계속 내려가는 화면과 배치는 키셋입니다.
실무에서는 앞쪽 몇 페이지는 OFFSET으로 충분하고, 깊은 페이지가 실제로 발생하는지를 먼저 확인하는 게 현실적입니다. 사용자가 3페이지 이상 안 넘긴다면 굳이 키셋으로 갈 필요가 없습니다.
ORDER BY가 전제입니다. 정렬 키에 인덱스가 없고 대상 건수가 많으면, 페이징 방식과 무관하게 정렬 자체가 병목이 됩니다.$top/$skip은 개념적으로 OFFSET 방식입니다. 백엔드가 대량 테이블이면 deep paging 문제가 그대로 나타날 수 있습니다.OFFSET은 건너뛸 행도 DB가 일단 만들어냅니다. 깊은 페이지일수록 느려집니다.다음 ⑥편에서는 같은 대량 조회를 메모리 관점에서 봅니다. 페이징과 비슷해 보이지만 목적이 다른 PACKAGE SIZE와 커서 이야기입니다.
Disclaimer — 이 포스트는 AI(Claude)를 활용하여 작성된 초안을 바탕으로 검수 및 보완하여 작성되었습니다. 내용 중 오류나 오타가 있다면 댓글로 알려주시면 감사하겠습니다.