04.07 (Refactoring)
2023. 4. 7. 23:01ㆍ개발일지
우리가 런칭하는 사이트에 검색 기능 로딩 시간이 길어서 Refactoring을 하기로 결정을 하였습니다.
@Transactional(readOnly = true)
public Page<PostResponseDto> getPosts(String category, Sort sort, String lat, String lng, int page, int size, Member member) {
List<PostResponseDto> postResponseDtos = new ArrayList<>();
Pageable pageable = PageRequest.of(page, size);
List<Post> posts = postRepository.findByCategory(category);
// 위도, 경도
Double usrtLat = Double.parseDouble(lat);
Double usrtLng = Double.parseDouble(lng);
// PostResponseDto 생성
buildResponseDtos(member, postResponseDtos, posts, usrtLat, usrtLng ,sort);
// 정렬 메서드
sort(sort, postResponseDtos);
// 페이지네이션
int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), postResponseDtos.size());
return new PageImpl<>(postResponseDtos.subList(start, end), pageable, postResponseDtos.size());
}
검색 기능에 공통적으로 쓰고있는
// PostResponseDto 셍성
private void buildResponseDtos(Member member, List<PostResponseDto> postResponseDtos, List<Post> posts, Double usrtLat, Double usrtLng, Sort sort) {
for (Post p : posts) {
Double postLat = Double.parseDouble(p.getLat());
Double postLng = Double.parseDouble(p.getLng());
double distance = distance(usrtLat, usrtLng, postLat, postLng);
p.getReviews().sort(Comparator.comparing(Review::getCreatedAt).reversed());
log.info("정렬 완료");
List<ReviewResponseDto> reviewResponseDtos = new ArrayList<>();
Integer reviewStar = 0;
int count = 0;
for (Review r : p.getReviews()) {
reviewResponseDtos.add(ReviewResponseDto.from(r));
reviewStar += r.getStar();
count += 1;
log.info(p.getCategory(),"for문 성공");
}
int starAvr = 0;
if (count != 0) {
starAvr = Math.round(reviewStar / count);
log.info("if문 count 가 0이 아닐때");
}
Likes likes = likesRepository.findByPostIdAndMemberId(p.getId(), member.getId());
boolean isLike = likes != null;
postResponseDtos.add(PostResponseDto.builder()
.post(p)
.star(starAvr)
.distance(distance)
.reviewCount(count)
.isLike(isLike)
.build());
}
sort(sort , postResponseDtos);
log.info("sort 성공");
}
이 메서드를 시간복잡도를 줄여보려고 QueryDSL로 Refactoring을 시도하였습니다. 우선 Repository 아래와 같이 로직을 짜고
@Override
public List<Post> find(String category){
return queryFactory.selectFrom(post)
.leftJoin(post.reviews, review1).fetchJoin()
.where(post.category.eq(category))
.distinct()
.fetch();
}
Service에 가서
private void buildResponseDtos(Member member, List<PostResponseDto> postResponseDtos, List<Post> posts, Double usrtLat, Double usrtLng, Sort sort) {
log.info("buildResponseDtos() 메서드 시작");
for (Post p : posts) {
Double postLat = Double.parseDouble(p.getLat());
Double postLng = Double.parseDouble(p.getLng());
double distance = distance(usrtLat, usrtLng, postLat, postLng);
p.getReviews().sort(Comparator.comparing(Review::getCreatedAt).reversed());
int reviewStar = p.getReviews().stream()
.mapToInt(Review::getStar)
.sum();
int count = p.getReviews().size();
int starAvr = 0;
if (count != 0) {
starAvr = Math.round(reviewStar / count);
}
Likes likes = likesRepository.findByPostIdAndMemberId(p.getId(), member.getId());
boolean isLike = likes != null;
postResponseDtos.add(PostResponseDto.builder()
.post(p)
.star(starAvr)
.distance(distance)
.reviewCount(count)
.isLike(isLike)
.build());
}
sort(sort , postResponseDtos);
log.info("buildResponseDtos() 메서드 종료");
}
for문을 빼버리니 시간복잡도가 굉장히 짧아졌습니다. 항상 리팩토링을 해서 서버에서 작동하는 쿼리를 최대한 최소화를 시켜서 속도 및 서버가 터지지 않게 계속 고민하고 시도해봐야 되는 도전정신을 배웠습니다!
'개발일지' 카테고리의 다른 글
04.09 TIL (테스트 코드) (0) | 2023.04.09 |
---|---|
04.08 TIL (테스트 코드) (0) | 2023.04.09 |
04.06 TIL (Nginx) (0) | 2023.04.07 |
04.04 TIL (SSE) (0) | 2023.04.07 |
04.03 TIL (0) | 2023.04.03 |