다음과 같은 사용자 테이블이 존재한다.
CREATE TABLE users (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL
);
아래 쿼리는 사용자 목록을 페이지 단위로 조회하기 위해 사용된다.
SELECT *
FROM users
ORDER BY username
LIMIT 5 OFFSET 15;
이와 같은 LIMIT + OFFSET 기반 페이징 방식에 대해 올바른 설명을 모두 고르시오.
(복수 선택 가능)
A. 이 쿼리는 5번부터 15번까지의 행을 반환한다.
B. 결과의 일관성을 보장하려면 반드시 ORDER BY 절이 필요하다.
C. OFFSET 값이 커질수록 성능 저하가 발생할 수 있다.
D. LIMIT 절 자체는 성능에 부정적인 영향을 준다.
✅ 정답은 B, C 이다.
| 선택지 | 정답 여부 |
|---|---|
| A | ❌ |
| B | ✅ |
| C | ✅ |
| D | ❌ |
이제 왜 그런지 하나씩 해부하자.
SELECT *
FROM users
ORDER BY username
LIMIT 5 OFFSET 15;
이 쿼리의 의미는 다음과 같다.
username 기준으로 정렬된 결과에서
앞에서 15개를 건너뛰고(skip)
그 다음 5개 행을 반환하라
즉,
이다.
이 문장은 아주 흔한 오해다.
OFFSET 15 → 앞의 15개 행을 버림
LIMIT 5 → 그 다음 5개를 가져옴
👉 반환되는 것은 16번째부터 20번째 행
| 번호 | 처리 |
|---|---|
| 1 ~ 15 | 건너뜀 |
| 16 ~ 20 | 반환 |
따라서
❌ “5–15번 행”이라는 설명은 완전히 틀리다.
이건 핵심 정답이다.
SELECT * FROM users LIMIT 5 OFFSET 15;
즉,
페이지네이션에서 ORDER BY는 선택이 아니라 필수이다.
그래서 이 선택지는 참이다.
이건 실무에서 아주 중요한 포인트다.
LIMIT 5 OFFSET 100000;
MySQL은 내부적으로 이렇게 한다.
ORDER BY username)👉 버리는 행도 전부 읽는다
즉,
따라서 이 선택지는 참이다.
이 문장은 그럴듯해 보이지만 틀렸다.
LIMIT은 “얼마나 가져올지”를 제한하는 역할성능 문제의 원인은:
LIMIT ❌따라서
LIMIT 자체가 느린 게 아니라
OFFSET이 문제다
이 선택지는 거짓이다.
LIMIT + OFFSET 기반 페이지네이션은 구현은 간단하지만,
OFFSET 값이 커질수록 성능 저하가 발생하며,
결과의 일관성을 보장하기 위해 ORDER BY 절이 반드시 필요하다.
이 문제의 숨은 의도는 이거다.
다음과 같은 쿼리는 흔히 사용되는 페이지네이션 방식이다.
SELECT *
FROM users
ORDER BY username
LIMIT 5 OFFSET 100000;
이 방식은 OFFSET 기반 페이지네이션이라 불린다.
구현은 간단하지만, 데이터가 많아질수록 심각한 성능 문제가 발생한다.
MySQL 엔진은 위 쿼리를 다음 순서로 처리한다.
username 기준으로 전체 결과를 정렬한다.이때 중요한 점은 다음과 같다.
즉, OFFSET 방식은 페이지 번호가 커질수록 비효율이 누적되는 구조이다.
이를 해결하기 위한 방식이 Keyset Pagination (Seek Method) 이다.
핵심 아이디어는 단순하다.
“앞의 N개를 버리지 말고,
이전 페이지의 마지막 값 이후부터 바로 조회하자”
예를 들어 이전 페이지의 마지막 username 값이 'mike'라면 다음 페이지는 다음과 같이 조회한다.
SELECT *
FROM users
WHERE username > 'mike'
ORDER BY username
LIMIT 5;
Keyset 방식에서는
OFFSET n → 없음
이 된다.
즉,
다음 조건이 만족되면 성능은 극적으로 개선된다.
CREATE INDEX idx_users_username ON users(username);
이 경우 MySQL은
'mike' 이후 위치로 즉시 이동이는 내부적으로 B-Tree의 특정 노드로 바로 seek하는 동작이다.
OFFSET 방식:
페이지가 뒤로 갈수록 점점 느려짐 (O(n))
Keyset 방식:
항상 일정한 속도 유지 (O(page_size))
즉, 1페이지든 10만 페이지든 읽는 행 수는 거의 동일하다.
| 구분 | OFFSET 방식 | Keyset 방식 |
|---|---|---|
| 읽는 행 수 | OFFSET + LIMIT | LIMIT |
| 뒤 페이지 성능 | 급격히 저하 | 일정 |
| 인덱스 활용 | 제한적 | 매우 효율적 |
| 대용량 데이터 | 부적합 | 적합 |
OFFSET 방식은 다음 상황에서 문제가 된다.
이런 데이터들은 공통적으로
Keyset 방식은 이런 상황에서 사실상 표준이다.
Keyset Pagination에도 조건이 있다.
ORDER BY username (고정)
정렬 기준이 바뀌면 페이지 연속성이 깨진다.
username이 중복 가능하다면 다음과 같이 보완한다.
WHERE (username, id) > ('mike', 123)
ORDER BY username, id
LIMIT 5;
이는 정렬의 결정성을 보장하기 위함이다.
OFFSET 기반 페이지네이션은 앞의 행을 모두 스캔해야 하므로 페이지가 뒤로 갈수록 느려지지만,
Keyset Pagination은 인덱스를 이용해 마지막 키 이후로 바로 탐색하기 때문에 대용량 데이터에서도 일정한 성능을 유지한다.