커서 기반, Offset 기반 페이지네이션 With Typeorm

jimin·2022년 7월 10일
0

Database

목록 보기
1/1

페이지네이션이란?

한정된 네트워크 자원을 효율적으로 활용하기 위해 특정한 정렬 기준에 따라 데이터를 분할하여 가져오는 것

1) 오프셋 페이징

  • DB의 offset쿼리를 사용하여 ‘페이지’ 단위로 구분하여 요청/응답

2) 커서 페이징

  • Cursor 개념을 사용하여 사용자에게 응답해준 마지막 데이터 기준으로 다음 n개 요청/응답

1. 오프셋 기반 페이지네이션 (Offset-based Pagination)

SELECT * FROM `user` ORDER BY id DESC LIMIT 20, 40
 await this.userRepository
        .createQueryBuilder("user")
        .offset(0).limit(10).getRawMany()

offset : 1부터 시작하는 페이지
limit : 한번에 불러올 페이지

가장 쉽고 빠르게 페이징 할수 있는 방법이지만 해당 방법을 사용시 몇가지 문제점이 생긴다.

  • 각각의 페이지를 요청하는 사이에 데이터의 변화가 있는 경우 중복 데이터 노출
  • 대부분의 RDBMS 에서 OFFSET 쿼리의 퍼포먼스 이슈
    - 점점 더 느려지게 된다.

2. 커서 기반 페이지네이션 (Cursor-based Pagination)

클라이언트가 가져간 마지막 row의 순서상 다음 row들을 n개 요청/응답하게 구현

이 전에 받은 데이터 이후 몇개를 주세요 라고 요청하는 방식
해당 방식은 Cursor을 하나 설정해줘야한다. 고유한 값으로 해당 커서는 CONSAT() 을 이요해서 만들기도 하고 id 값을 사용하기도 한다.

가장 간단하게는 id기준으로 10개씩 보내줬다. (정렬 후)
이렇게 하면 처음 호출시에는 10개의 id를 그 후부터는 이전에서 보내줬던 마지막 아이디를 넣어주면 그 뒤 10개를 보내주는 아주 간단한 커서기반 페이지네이션이 된다.

    if(cursor){
            queryBuilder.andWhere('user.id < :cursor' , { cursor })
    }

    queryBuilder.orderBy("user.id", "DESC").offset(0).limit(10).getRawMany()

두가지 parameter 기준 정렬도 가능하다.

SELECT id, name, age
	FROM `user`
	WHERE 
		(age > 20
			OR
    (age = 20 AND id > 14))
	ORDER BY price ASC, id ASC
	LIMIT 10

하지만 해당 방법으로 페이징을 할 경우 또 두가지 문제점이 있어 커스텀 CURSOR을 사용하는 경우가 많다.
1. 대부분의 RDBMS는 WHERE에 OR-clause 를 사용하면 인덱싱을 제대로 못 태움.
2. 클라이언트가 ORDER BY에 걸려있는 모든 필드를 알아야하고, 매 페이지 요청시마다 이 값들을 전부 보내야 함.

profile
안녕하세요 백엔드 개발자 지민입니다.

0개의 댓글