질문 하나 할게: 인터넷 쇼핑몰에서 한 페이지에 상품이 너무 많으면 어떻게 해? 맞아, 다음 페이지를 열지! 근데 그 뒤에서 무슨 일이 일어날까? 바로 SQL의 마법이야 — OFFSET 명령어로 행을 건너뛰는 거지. 오늘은 OFFSET이 뭔지, 왜 필요한지, 어떻게 쓰는지, 그리고 왜 데이터 페이지네이션의 핵심인지 알려줄게.
OFFSET은 SQL에서 결과에서 지정한 만큼의 행을 건너뛰게 해주는 키워드야. 책 페이지 넘기는 거랑 비슷해: 처음 10줄을 "건너뛰고" 11번째 줄부터 볼 수 있지.
문법
SELECT 컬럼1, 컬럼2
FROM 테이블
OFFSET 건너뛸_행_수;
OFFSET— 행을 건너뛰는 키워드야.- 건너뛸_행_수 — 건너뛸 행의 개수야.
OFFSET 간단 사용 예시
예를 들어, students 테이블에 이런 데이터가 있다고 해보자:
| id | name | age |
|---|---|---|
| 1 | 알리사 | 22 |
| 2 | 보브 | 24 |
| 3 | 클라라 | 23 |
| 4 | 단 | 21 |
| 5 | 에바 | 25 |
우리는 세 번째 학생부터 모두 출력하고 싶어. 이럴 때 이렇게 쿼리하면 돼:
SELECT *
FROM students
OFFSET 2;
결과:
| id | name | age |
|---|---|---|
| 3 | 클라라 | 23 |
| 4 | 단 | 21 |
| 5 | 에바 | 25 |
SQL이 처음 두 줄(알리사랑 보브)을 "건너뛰고" 세 번째 줄부터 결과를 보여주는 거야. 책갈피 쓰는 거랑 똑같지: "이 페이지는 이미 읽었으니까 다음 페이지로 넘어가자".
OFFSET과 LIMIT 같이 쓰기
OFFSET은 보통 LIMIT이랑 같이 써. 이렇게 하면 행을 건너뛰면서 결과를 원하는 개수만큼만 가져올 수 있어. 이게 바로 페이지네이션(page — 페이지) 만들 때 엄청 유용하지 — 데이터를 여러 줄씩 나눠서 보여줄 수 있으니까.
예를 들어, 한 번에 2개씩만 보여주고, 세 번째 줄부터 시작하고 싶으면 쿼리는 이렇게 돼:
SELECT *
FROM students
LIMIT 2
OFFSET 2;
결과:
| id | name | age |
|---|---|---|
| 3 | 클라라 | 23 |
| 4 | 단 | 21 |
동작 원리:
OFFSET 2가 처음 두 줄(알리사, 보브)을 건너뛰어.LIMIT 2가 남은 것 중에서 두 줄만 가져와.
페이지네이션 만들기
이제 제일 재밌는 부분 — 페이지네이션 만들기! 예를 들어 학생 목록을 보여주는 웹앱을 만든다고 해보자. 한 페이지에 2개씩만 보여주고 싶어. 어떻게 할까?
기본 원리:
- 첫 번째 페이지는 0줄 건너뛰기:
OFFSET 0. - 두 번째 페이지는 2줄 건너뛰기:
OFFSET 2. - 세 번째 페이지는 4줄 건너뛰기:
OFFSET 4. - 계속 반복...
예시: 두 번째 페이지 출력
첫 번째 페이지에는 1, 2번(알리사, 보브)이 나오고, 두 번째 페이지에는 3, 4번(클라라, 단)이 나와.
SELECT *
FROM students
ORDER BY id
LIMIT 2
OFFSET 2;
결과:
| id | name | age |
|---|---|---|
| 3 | 클라라 | 23 |
| 4 | 단 | 21 |
예시: 세 번째 페이지 출력
세 번째 페이지에는 5, 6번(있으면)이 나와.
SELECT *
FROM students
ORDER BY id
LIMIT 2
OFFSET 4;
결과:
| id | name | age |
|---|---|---|
| 5 | 에바 | 25 |
OFFSET 계산 공식
페이지네이션 시스템 만들 때 자동화하려면 이런 공식을 쓸 수 있어:
OFFSET = (페이지_번호 - 1) * 페이지당_출력_개수
예시:
- 첫 번째 페이지:
(1 - 1) * 2 = 0. - 두 번째 페이지:
(2 - 1) * 2 = 2. - 세 번째 페이지:
(3 - 1) * 2 = 4.
성능 관련 중요한 팁
큰 테이블에서 OFFSET을 쓰면, 특히 뒤쪽 페이지에서 비효율적일 수 있어. 이유는 PostgreSQL이 건너뛸 행도 다 읽어야 하기 때문이야. 예를 들어 OFFSET 10000이면, DBMS가 처음 10,000줄을 다 훑고 나서 결과를 주는 거지. 이런 경우엔 페이지네이션 마커로 유니크 id를 쓰는 등 다른 방법을 고려해봐.
대안: 커서(cursor)로 페이지네이션
최적화를 위해 "커서" 방식도 쓸 수 있어. OFFSET으로 행을 건너뛰는 대신, 이전 페이지에서 마지막으로 본 행의 id를 기억해서 다음 쿼리를 만드는 거야:
SELECT *
FROM students
WHERE id > 마지막_출력_id
ORDER BY id
LIMIT 2;
이 방식은 큰 테이블에서 훨씬 빠를 수 있어.
페이지네이션 실전 활용
페이지네이션은 대부분의 웹앱에서 써: 쇼핑몰, 블로그, 관리자 패널 등. 예를 들면:
- 쇼핑몰에서 상품 목록 보여주기;
- CRM 시스템에서 사용자 목록 출력;
- 뉴스 피드 페이지별로 보여주기.
또, 데이터가 많을 때 분석할 때도 페이지네이션으로 조금씩 나눠서 볼 수 있어서 좋아.
OFFSET 쓸 때 흔한 실수
OFFSET 쓸 때 가끔 헷갈릴 수 있어, 특히 처음 배울 때. 대표적인 실수 몇 가지 알려줄게:
정렬 누락. ORDER BY를 안 쓰면 OFFSET 결과의 행 순서가 랜덤이 될 수 있어.
잘못된 쿼리:
SELECT * FROM students
OFFSET 5;
올바른 쿼리:
SELECT * FROM students
ORDER BY id
OFFSET 5;
OFFSET 값 잘못 지정. 너무 큰 값을 넣으면 결과가 빈 집합이 될 수 있어.
성능 문제. 아까 말했듯이, 뒤쪽 페이지에서 OFFSET이 크면 비효율적이야.
필터 누락. OFFSET과 LIMIT을 WHERE 없이 쓰면 필요 없는 데이터까지 가져와서 성능이 떨어질 수 있어.
연산자 순서. SQL에서 연산자 순서는 고정이야: LIMIT 먼저, 그 다음 OFFSET. 생략은 가능하지만 순서 바꾸면 안 돼.
GO TO FULL VERSION