2023. 4. 13. 10:20ㆍ개발일지
Querydsl을 통해 성능을 개선하기 위해 두가지 변경사항을 적용 시켜 봤다.
1. @Transactional(readOnly = true) 사용
2. Querydsl 에서의 paging 처리
1. @Transactional(readOnly = true) 사용
@Repository
public class PostRepositoryCustomImpl extends QuerydslRepositorySupport implements PostRepositoryCustom{
..... 생략
}
조회만을 위한 Querydsl 클래스에 @Transactional(readOnly = true) 을 사용하여 성능을 향상시켜줬다.
@Transactional(readOnly = true) 을 사용했을때 장점이 있다.
1. 롤백 로그를 생성하지 않아 성능이 향상된다.
2. 동시성 처리를 통해 성능이 향상된다.
@Repository
@Transactional(readOnly = true)
public class PostRepositoryCustomImpl extends QuerydslRepositorySupport implements PostRepositoryCustom{
..... 생략
}
이렇게 어노테이션만 추가해도 성능적인 부분을 개선할수 있었다.
2. Querydsl 에서의 paging 처리
// 게시글 카테고리별 (전체)조회
@LogExecutionTime
@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.find(category); // 수정할 부분
Double usrtLat = Double.parseDouble(lat);
Double usrtLng = Double.parseDouble(lng);
buildResponseDtos(member, postResponseDtos, posts, usrtLat, usrtLng, sort);
int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), postResponseDtos.size());
// 수정할 부분
return new PageImpl<>(postResponseDtos.subList(start, end), pageable, postResponseDtos.size());
}
현재 paging 처리를 getPosts 메서드 안에서 하고있다.
이럴 경우 DB에서 게시글 전체를 불러와서 paging 처리를 해준뒤에 정보를 보내게 된다.
문제는 size가 10일경우 10개의 게시글만 불러와도 되는데 1000개면 1000개 다 불러와서 처리를 하는것은 비효율 적이라 생각했다.
이를 개선하기 위해서 Querydsl을 통해 게시글을 불러올때 size만큼 불러올수있게 paging처리를 Querydsl 에서 해주는 방법을 찾아봤다.
@Override
public List<Post> find(String category, Pageable pageable) {
return queryFactory.selectFrom(post)
.leftJoin(post.reviews, review1).fetchJoin()
.where(post.category.eq(category))
.distinct()
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}
Querydsl 에서 offset()과 limit()를 이용하였다.
offset() 메서드는 어디를 시작 점으로 할것인지, limit() 는 몇개를 가져올 것인지 정하는 메서드이다.
@Override
public long countByCategory(String category) {
Long count = queryFactory.select(post.id.countDistinct())
.from(post)
.where(post.category.eq(category))
.fetchOne();
return Optional.ofNullable(count).orElse(0L);
}
category에 맞는 전체 게시글 개수를 구하는 메서드를 생성한후 PageImpl() 에 있는 전체 개수에 넣어준다.
필요없어진 getPosts내의 paging 처리하는 부분을 날려주고 코드를 적용시키면
@LogExecutionTime
@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.find(category, pageable);
Double usrtLat = Double.parseDouble(lat);
Double usrtLng = Double.parseDouble(lng);
buildResponseDtos(member, postResponseDtos, posts, usrtLat, usrtLng, sort);
long totalCount = postRepository.countByCategory(category);
return new PageImpl<>(postResponseDtos, pageable, totalCount);
}
이렇다.
성능을 비교해 보면
첫 호출시 269.2ms 에서 168ms(156% 향상)
두번째 호출시 191ms 에서 97ms(196%향상)
의미있는 성능개선을 볼 수 있었다.
느낀점!
getPosts()메서드를 가지고 이틀동안 리팩토링을 진행해봤다.
생각이 나는대로 코드를 짯을때 보다 코드 리팩토링을 하면서 이것저것 적용해보다보니 최대 5배까지 빨라지는 결과를 경험해봤다.
중복된 코드는 없는지, paging처리를 왜하는지, Querydsl을 왜 사용하는지 또 어떻게 쓰는지 에 따라 같은 기능을 하는 코드 일 지라도 응답속도가 굉장히 차이가 났다.
이번 프로젝트때는 주먹구구식으로 코드를 짜고 리팩토링을 하는방식으로 했지만
좀 더 실력을 키워 코드를 하나를 짜더라도 좀 더 깊이있게 생각하고 적용시킬수 있는 개발자가 될 수 있도록 노력해봐야겠다.
'개발일지' 카테고리의 다른 글
04.16 TIL LINUX 와 권한 (0) | 2023.04.16 |
---|---|
04.15 TIL (서버) (0) | 2023.04.15 |
04.10 TIL (0) | 2023.04.10 |
04.09 TIL (테스트 코드) (0) | 2023.04.09 |
04.08 TIL (테스트 코드) (0) | 2023.04.09 |