RDB에서 페이징 쿼리의 필요성을 설명해 주세요.

백엔드와 관련된 질문이에요.

페이징 쿼리(Paging Query) 는 전체 데이터를 부분적으로 나누어 데이터를 조회하거나 처리할 때 사용됩니다. 데이터를 상대적으로 작은 단위로 나누어 처리하기 때문에 데이터베이스나 애플리케이션의 리소스 사용 효율이 증가하며, 로직 처리 시간을 단축 시킬 수 있습니다. MySQL에서 페이징 쿼리는 일반적으로 LIMIT, OFFSET 구문을 사용하여 작성합니다.

select *
from subscribe
limit 500
offset 0;

LIMIT, OFFSET 방식 페이징 쿼리의 단점은 무엇이고, 어떻게 해결할 수 있나요?

LIMIT, OFFSET 방식의 페이징 쿼리는 뒤에 있는 데이터를 읽을 수록 점점 응답 시간이 길어질 수 있는데요. 왜냐하면, DBMS는 지정된 OFFSET 수만큼 모든 레코드를 읽은 이후에 데이터를 가져오기 때문입니다. 이 문제를 해결하기 위해서 OFFSET을 활용하지 않는 페이징 쿼리를 사용하는 것이 대표적입니다. 예를 들어, 다음과 같은 테이블이 있다고 가정하겠습니다.


create table subscribe (
   id int not null auto_increment,
   deleted_at datetime null,
   created_at datetime not null,
   primary key(id),
   key idx_deleted_at_id(deleted_at, id)
);

이때, 특정 기간 동안 구독을 해제한 사용자를 조회하는 쿼리는 다음과 같습니다.

select *
from subscribe
where
    deleted_at >= ? and deleted_at < ?

OFFSET을 사용하지 않는 페이징은 이전 페이지의 마지막 데이터 값을 기반으로 다음 페이지를 조회합니다. 이때, 상황에 따라서 첫 페이지 조회 쿼리와 N 회차 쿼리의 모양이 다를 수 있습니다. 위 예제에서 첫 페이지를 조회하는 쿼리는 다음과 같이 작성할 수 있습니다.

select *
from subscribe
where
    deleted_at >= ? and deleted_at < ?
order by deleted_at, id
limit 10;

그리고 첫 페이지 이후의 페이지는 이전에 조회된 페이지의 마지막 값을 기반으로 다음 페이지를 조회합니다. 만약, 이전 페이지의 마지막 값의 deleted_at이 '2024-01-01'이고, 식별자가 78이라면 다음과 같은 쿼리가 작성됩니다.

select *
from subscribe
where
   # deleted_at이 같은 케이스를 대응
   (deleted_at = '2024-01-01 00:00:00' and id > 78) or
   # 마지막 데이터 이후 데이터 조회
   (deleted_at > '2024-01-01 00:00:00' and deleted_at < ?)
order by deleted_at, id
limit 10;

추가 학습 자료를 공유합니다.