인스타그램과 같이 피드에 여러개의 이미지가 있고, 그 이미지들 중 첫번째 이미지만 가져오는 로직을 작성하고 있습니다.
첫번째 쿼리의 경우에는 보시는바와 같이 FeedImage 엔티티에서, 해당 feedImage의 feed의 id 기준으로 커서를 설정하였으며, (왜냐면 사용자에게 보여줄 때에는 피드 순으로 보여주어야 하기 때문에) writer가 user와 같은 경우 해당 이미지를 선택하는 방식입니다.
@Override
public List<FeedImage> findByFeedWriterAndIdLessThanOrderByIdDesc(User user, Long cursorId) {
List<FeedImage> feedImageList = queryFactory
.selectFrom(feedImage)
.where(feedImage.feed.id.lt(cursorId)
.and(feedImage.feed.writer.eq(user)))
.orderBy(feedImage.feed.id.desc())
.limit(20)
.fetch();
return feedImageList;
}
그렇게하자, 비교적 긴 시간인 약 2초가 걸렸습니다.
어떻게 개선을 할 수 있을까 라는 생각을 하게 되었고, FeedImage를 가져오는 로직이지만, Feed를 기준으로 쿼리를 작성한 후, 선택된 feed에 해당하는 이미지를 가져오면 될 것 같다는 생각이 들었습니다.
그래서 바로 코드를 작성하여 쿼리를 확인해보았습니다.
@Override
public List<FeedImage> findByFeedWriterAndIdLessThanOrderByIdDesc(User user, Long cursorId) {
List<Feed> feedList = queryFactory
.selectFrom(feed)
.where(feed.id.lt(cursorId)
.and(feed.writer.eq(user)))
.orderBy(feed.id.desc())
.limit(20)
.fetch();
// 가져온 feed ID 목록 추출
List<Long> feedIds = feedList.stream()
.map(Feed::getId)
.collect(Collectors.toList());
// 두 번째 쿼리: feed ID 목록을 이용해 첫번째 피드 이미지만 가져오기
List<FeedImage> results = queryFactory
.selectFrom(feedImage)
.where(feedImage.feed.id.in(feedIds)
.and(feedImage.number.eq(0)))
.fetch();
// Feed ID 기준으로 정렬
results.sort(Comparator.comparing(feedImage -> feedImage.getFeed().getId()));
return results;
}
속도가 10배 정도 차이남을 확인할 수 있었습니다.
또한, 위와 커서 ID가 상이한데, 아래 로직이 맞음을 DB에서 확인할 수 있었습니다.
이렇게, 같은 로직도 다르게 작성하면 속도의 차이가 많이 남을 확인할 수 있었으며, 오프셋 기반 페이지네이션부터 커서 기반 페이지네이션, 그리고 쿼리DSL을 통한 속도 증진을 통해 처음 시작인 20초에서 300ms 까지 성능을 개선할 수 있었습니다. 🥰
'프로젝트' 카테고리의 다른 글
[Spring/MongoDB] 스프링 프로젝트에 MongoDB 연결하기 (설치 및 연결) (0) | 2024.07.12 |
---|---|
[트러블슈팅] 객체 삭제 시 org.hibernate.StaleObjectStateException 에러 발생 (0) | 2024.06.24 |
[Spring/QueryDSL] Fetch Join이랑 limit은 함께 못쓴다고요 ? (1) | 2024.06.13 |
[Java] Record란? & 프로젝트에 Record 적용해보기 (0) | 2024.06.12 |
[Restagram] 리팩토링 (0) | 2024.06.11 |