현재 서비스에서는 게시글 조회 시 최신순 정렬이 기본값이다.
원래 기존에 작성해주신 코드는, 쉬운 이해를 위해 아래 기본적인 코드로 예시를 작성하겠다.
@Override
public List<Post> getPosts(int pageNum, int pageSize) {
return queryFactory.selectFrom(post)
.orderBy(post.createdAt.desc()) // 최신순으로 정렬
.offset((pageNum - 1) * pageSize) // 페이지 번호를 기준으로 OFFSET 계산
.limit(pageSize) // 한 페이지에 표시할 결과 수
.fetch();
}
jpa 쿼리에서도 offset 쿼리가 포함되어 나가고,
querydsl도 보통 이런 식이다. (slice 처리 코드 등 세부 코드는 포함하지 않았다.)
그런데 이렇게 조회를 하게 되면, 전에 읽었던 행들을 다시 또 읽어야 하기 때문에 offset이 증가할 수록 탐색 속도가 느려진다는 문제가 생긴다.
이제는 많이 유명해진 no-offset 방식인데, 생각보다 적용하지 않은 코드들이 종종 보인다.
아래는 no-offset 방식을 적용한 쿼리다.
@Override
public List<Post> getPosts(Long lastPostId, int pageSize) {
return queryFactory.selectFrom(post)
.where(Objects.isEmpty(lastPostId) ? null : dailyLife.id.lt(lastPostId))
.orderBy(post.createdAt.desc()) // 최신순으로 정렬
.limit(pageSize) // 한 페이지에 표시할 결과 수
.fetch();
}
여기서 null 체크를 해주는 이유는,
만약 맨 첫 페이지를 조회할 때, 클라이언트 입장에서는 현재 db에서 제일 최신 게시글 id를 알 수가 없기 때문이다.
그래서 id가 null이라면, where절이 없이 최신순으로 첫 페이지를 조회하는 것이고,
id값이 존재한다면 where절을 추가해서 이전 게시글 id보다 작은 id를 가진 게시글만 조회하게끔 한다.
현재 서비스에서 테스트한 결과, 위 두 코드의 성능 차이는 이러하다.
위 사진이 offset 적용 시, 그리고 아래 사진이 no-offset 방식을 적용했을 때이다.
물론 데이터 양도 많지 않고, where절이나 다른 코드에 의해 성능 차이가 날 수 있지만,
확연히 빠른 성능을 보이는 것은 사실이다..!
'대충 넘어가지 않는 습관을 위한 기록' 카테고리의 다른 글
Gemini api pro 연동 기록 - RestTemplate (0) | 2024.11.12 |
---|---|
SSE를 이용한 실시간 알림 구현 기록 (3) | 2024.10.15 |
ArgumentResolver 응용 기록 (0) | 2024.08.13 |
GitHub Actions 워크플로우 이벤트 수동 전환 (0) | 2024.07.18 |
FeignClient를 이용한 소셜 로그인 (카카오, 구글) (0) | 2024.07.11 |