HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
⚽
SFAM (스포츠 패밀리) Portfolio
/
커서페이징 데이터 유실 문제 해결

커서페이징 데이터 유실 문제 해결

Tags
이슈대응

페이징 기술 자세히 알아보기

페이징 처리
 

요약


이슈: 최근 수정 일자 기준으로 데이터를 가져오는 중 일부 데이터가 유실되는 문제를 발견했습니다.
해결: 수정 일자 중복 시 레코드를 구분할 수 없는 것이 원인이었습니다. 레코드를 구분할 수 있는 칼럼을 추가하고 정렬기준을 리팩터링하여 이슈를 해결했습니다.

문제점


  • 커서 페이징에 대해 테스트 코드로 테스트하던 도중 중복 데이터가 유실되는 문제를 발견했습니다.

원인 분석


notion image
notion image
  • 처음 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)를 역순으로 정렬 해 쿼리에 조건을 추가 했습니다.
notion image
 
3개씩 페이징 한다고 가정 했을 때, 제가 처음 작성했던 쿼리는 다음과 같습니다. 얼핏 봤을 때에는 문제 없이 페이징 되는 듯 해 보였습니다.
SELECT * FROM post WHERE id < ${cursorId} and updatedAt <= ${cursorUpdatedAt} order by updatedAt desc, id desc limit 3;
 
# 처음 데이터 3개 불러오기 (마지막 데이터 id = 14, updatedAt = 2022-08-14 09:53:39 SELECT * FROM post order by updatedAt desc, id desc limit 3;
notion image
 
# 다음 페이징 # cursor -> id = 14, updatedAt = 2022-08-14 09:53:39 # 13, 11, 10 SELECT * FROM post WHERE id < 14 and updatedAt <= '2022-08-14 09:53:39' order by updatedAt desc, id desc limit 3;
notion image
 
# 다음 페이징 # cursor -> id = 10, updatedAt = 2022-08-14 08:53:39 # 8, 7, 9 SELECT * FROM post WHERE id < 10 and updatedAt <= '2022-08-14 08:53:39' order by updatedAt desc, id desc limit 3;
notion image
 
⚠️ 하지만 해당 쿼리에는 문제점은 id는 항상 내림차순이 아님을 인지하고 있었어야 했습니다.
 
여러 게시물들을 수정해 다음 순서와 같이 데이터가 배치된 경우를 예로 보자면 이렇습니다.
notion image
 
자세히 탐구해보면
notion image
첫번째 페이징 후 커서는 updatedAt = 2022-09-04 12:00:00, id = 1을 가르킵니다. 다음 데이터를 불러올 때는 id가 1보다 작은 데이터가 없으므로 다른 데이터들을 조회할 수 없었습니다.
 
기존 쿼리로는 다음 데이터를 불러올 수가 없어 쿼리는 다음과 같이 변경했습니다.
SELECT * FROM post WHERE updatedAt < ${cursorUpdatedAt} // 최근 일자로 조회된 레코드를 긁어옴. or (id < ${cursorId} and updatedAt == ${cursorUpdatedAt} // 날짜가 같은 컬럼중 id가 더 작은걸로 가져오게 된다. 왜냐하면 order BY로 수정일자가 같으면 id로 내림차순 즉, 큰것부터 정렬했기 때문이다. ORDER BY updatedAt DESC, id DESC LIMIT 3;
 
쿼리를 변경해서 다시 자세히 보면
notion image
  1. 처음 3개의 데이터를 불러옵니다 cursor 는 id = 1, updatedAt = 2022-09-04 12:00:00 입니다.
  1. 그 다음은 updatedAt < 2022-09-04 12:00:00 조건으로 id가 18, 17, 6 … 인 값이 조회되고
    1. 2022-09-04 12:00:00:00과 중복되는 데이터가 없으므로 다음으로 넘어갑니다
      이제 cursor는 id = 6, updatedAt = 2022-09-04 08:00:00입니다.
  1. 다음으로 updatedAt < 2022-09-04 08:00:00 조건으로 3-a 부분이 조회됩니다.
    1. cursor updatedAt보다 작은 데이터들입니다.
      id < 6 AND updatedAt = 2022-09-04 08:00:00 조건으로 3-b 부분이 조회됩니다.
      cursor updatedAt과 같지만 id가 더 작은 것 들입니다.
 
중복 문제가 해결 되었습니다.