04.12 TIL(Querydsl 성능 향상)

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