페이징 기술 자세히 알아보기
페이징 처리요약
이슈: 최근 수정 일자 기준으로 데이터를 가져오는 중 일부 데이터가 유실되는 문제를 발견했습니다.
해결: 수정 일자 중복 시 레코드를 구분할 수 없는 것이 원인이었습니다. 레코드를 구분할 수 있는 칼럼을 추가하고 정렬기준을 리팩터링하여 이슈를 해결했습니다.
문제점
- 커서 페이징에 대해 테스트 코드로 테스트하던 도중 중복 데이터가 유실되는 문제를 발견했습니다.
원인 분석


- 처음 id가 18, 17, 14인 데이터를 불러 왔고 커서 값은 ‘2022-08-14 09:53:39’ 가 됩니다. 이제 다음 페이지를 불러올 경우에는 ‘2022-08-14 09:53:39’ 보다 전 시간의 데이터를 불러올 겁니다. 하지만 id가 13인 데이터도 마찬가지로 updatedAt이 ‘2022-08-14 09:53:39’ 이므로 스킵하게 됩니다. 결국, 잘못된 페이징으로 데이터 유실이 발생한 것입니다.
해결과정
과정
- 아래와 같이 수정일이 최신인 순으로 페이징해 출력하는 상황을 가정합니다. updatedAt이 같을 경우엔 중복되지 않는 값인 pk(id)를 역순으로 정렬 해 쿼리에 조건을 추가 했습니다.

3개씩 페이징 한다고 가정 했을 때, 제가 처음 작성했던 쿼리는 다음과 같습니다. 얼핏 봤을 때에는 문제 없이 페이징 되는 듯 해 보였습니다.



⚠️ 하지만 해당 쿼리에는 문제점은 id는 항상 내림차순이 아님을 인지하고 있었어야 했습니다.
여러 게시물들을 수정해 다음 순서와 같이 데이터가 배치된 경우를 예로 보자면 이렇습니다.

자세히 탐구해보면

첫번째 페이징 후 커서는 updatedAt = 2022-09-04 12:00:00, id = 1을 가르킵니다. 다음 데이터를 불러올 때는 id가 1보다 작은 데이터가 없으므로 다른 데이터들을 조회할 수 없었습니다.
기존 쿼리로는 다음 데이터를 불러올 수가 없어 쿼리는 다음과 같이 변경했습니다.
쿼리를 변경해서 다시 자세히 보면

- 처음 3개의 데이터를 불러옵니다 cursor 는 id = 1, updatedAt = 2022-09-04 12:00:00 입니다.
- 그 다음은 updatedAt < 2022-09-04 12:00:00 조건으로 id가 18, 17, 6 … 인 값이 조회되고
2022-09-04 12:00:00:00과 중복되는 데이터가 없으므로 다음으로 넘어갑니다
이제 cursor는 id = 6, updatedAt = 2022-09-04 08:00:00입니다.
- 다음으로 updatedAt < 2022-09-04 08:00:00 조건으로 3-a 부분이 조회됩니다.
cursor updatedAt보다 작은 데이터들입니다.
id < 6 AND updatedAt = 2022-09-04 08:00:00 조건으로 3-b 부분이 조회됩니다.
cursor updatedAt과 같지만 id가 더 작은 것 들입니다.
중복 문제가 해결 되었습니다.