| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- pagination
- 동적계획법
- 영속성 컨텍스트
- 자바의 정석
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초
- 정처기
- sqld
- document database
- 다이나믹프로그래밍
- Redis
- 게시판
- NoSQL
- cache
- VMware
- in-memory
- spring security
- 스프링 부트
- Spring Boot
- 실행 컨텍스트
- 호이스팅
- 스프링 시큐리티
- JPA
- 정보처리기사
- cursor
- DB파티션
- SQL
- 캐시
- 스프링부트
- db partition
- 레디스
- Today
- Total
FreeHand
OFFSET vs Cursor Pagination 정리 본문
목록 조회를 구현할 때 가장 많이 사용하는 방식은 크게 두 가지다.
- OFFSET 기반 페이징
- Cursor 기반 페이징
OFFSET 방식
SELECT *
FROM post
ORDER BY id DESC
LIMIT 20 OFFSET 10000;
OFFSET 방식은 위 쿼리처럼 LIMIT와 OFFSET을 사용해서 조회하는 방식이다.
id로 내림차순 정렬하고 10000개 건너뛰고 그다음 20개를 조회한다.
즉 아래와 같이 동작한다.
- 정렬 수행
- 10000개 row 읽음
- 10000개 버림
- 다음 20개 row 반환
20개를 조회하기 위해서 10020개를 조회한 것이다.
OFFSET이 커질수록 즉 페이지가 뒤로 갈수록 느려진다는 의미이다.
Cursor 방식
SELECT *
FROM post
WHERE id < 10000
ORDER BY id DESC
LIMIT 20;
Cursor 방식은 현재 위치(커서)를 기준으로 WHERE 조건절을 사용해서 조회하는 방식이다.
id = 10000을 찾아서 바로 20개 행만 읽는다.
항상 동일하게 20개만 읽으므로 뒤 페이지로 가도 조회 성능도 동일하다.
더 생각해 볼 점
인덱스 사용
SELECT *
FROM members
WHERE id < 10000
ORDER BY id DESC
LIMIT 20;
이경우에는 id 컬럼이 PK이므로 PK 인덱스를 사용해서 바로 20개만 조회할 수 있다.
SELECT *
FROM members
WHERE age < 30
ORDER BY age DESC
LIMIT 20;
만약 age 컬럼에 인덱스가 없으면 테이블 전체를 스캔하며 age < 30인 행을 찾고 정렬 후 20개를 반환한다.
즉 커서로 사용하는 컬럼에 인덱스가 없으면 결국 Full Table Scan이 발생한다.
복합 커서
SELECT *
FROM members
WHERE (age < {age})
ORDER BY age DESC, id DESC
LIMIT 20;
이렇게 작성하면 만약 age가 30인 회원이 여러 명인 경우, 이미 커서(age) 값이 30이므로 다음 페이지 조회에서 age가 30인 나머지 회원들은 나오지 않는다.
SELECT *
FROM members
WHERE (age < {age}) OR (age = {age} AND id < {id})
ORDER BY age DESC, id DESC;
그래서 위와 같이 (age, id) 복합 커서를 사용해야 누락 문제를 피할 수 있다.
이때도 마찬가지로 (age, id) 복합 인덱스가 필요하다.
UI / UX
OFFSET 방식은 페이지당 개수와 페이지 번호를 통해 조회를 할 수 있다. 즉 특정 페이지 번호로 이동이 가능하다.
반면 Cursor 방식은 "조회한 마지막 위치"에서 이어서 조회하는 성격이므로 특정 페이지로 이동할 수 없다.
따라서 페이지 번호가 있는 조회에서는 OFFSET이 더 적합하고, 마지막 위치에서 추가로 더 조회하는 무한 스크롤에는 Cursor가 적합하다고 볼 수도 있다.
'Database > RDB' 카테고리의 다른 글
| 옵티마이저와 실행계획 (4) | 2024.09.24 |
|---|---|
| [MySQL] 데이터 타입과 형 변환 (0) | 2023.11.05 |
| [MySQL] WITH절과 CTE (0) | 2023.11.05 |
| [MySQL] DELETE (0) | 2023.11.01 |
| [MySQL] UPDATE (0) | 2023.11.01 |