-
fetch join으로 성능 최적화프로젝트/Trend-Pick 2023. 8. 16. 15:41
프로젝트를 시작했을 때에는 JPQL를 간단히만 사용할 수 있었기 때문에 성능 문제에 대해서는 크게 고려를 안하고 값만 받아오는 데에 신경을 썼다.
public List<Post> findAllPost() { List<Post> AllPost = em.createQuery("select p from Post p", Post.class) .getResultList(); return AllPost; }
예를 들어 post를 전부 가져오는 findAllPost()이다. 하지만 컨트롤러에서 post의 member에 접근해서 조회해야하는 상황이 있다.
@GetMapping("/post_list") public List<PostDtoTitle> postList() { List<Post> findPosts = postService.findAllPost(); List<PostDtoTitle> postLists = findPosts.stream() .map(c -> { String imgUrl = Optional.ofNullable(c.getPostImg()) .map(PostImg::getImgUrl) .orElse(null); try { return new PostDtoTitle(c.getTitle(), c.getContent(), c.getPostTime(), imgUrl, c.getId(), c.getPost_member().getNickname()); } catch (Exception e) { e.printStackTrace(); } return null; }) .collect((Collectors.toList())); return postLists; }
try - catch 문에서 return으로 Dto를 보낼 때 c.getPost_member().getNickname()로 member 엔티티에 접근한다. 이럴 때에 map 루프를 돌면서 post 하나하나 각각 member를 조회하는 쿼리를 발생시킬 것이다. 결국 findAllPost() 쿼리에 각각의 member를 조회하는 N+1 쿼리 문제가 발생하게 되는 것이다.
fetch join으로 쿼리 최적화
public List<Post> findAllPost() { List<Post> AllPost = em.createQuery("select p from Post p join fetch p.post_member", Post.class) .getResultList(); return AllPost; }
fetch join을 사용하게 된다면 post를 select 할 때 post_member까지 같이 select 해오기 때문에 쿼리 한 번으로 해결해서 N+1 문제가 해결된다.
처음 컨트롤러를 만들었을 때에는 member.nickname()을 반환하지 않았지만 변경했을 때에 그냥 저렇게 넣어주고 끝내는 것이 아니라 다른 엔티티에 접근해서 같이 조회해야하는 경우가 생겼기 때문에 JPQL에서 쿼리 성능 최적화에 신경을 써야겠다는 생각이 들었다.
물론 member 등 다른 엔티티에 절대 접근할 일이 없다면 굳이 fetch join을 하지 않는 것이 좋다.
-> 필요없는 데이터를 가져오기 때문에
프로젝트를 시작했을 때에는 쿼리 성능 최적화를 아예 몰랐기 때문에 그냥 데이터만 받아오는 것을 최우선으로 개발을 진행했지만 며칠 전에 쿼리 최적화하는 방법을 공부했기 때문에 코드를 살펴보며 최적화가 필요한 코드들은 전부 최적화를 해야겠다.
'프로젝트 > Trend-Pick' 카테고리의 다른 글
join fetch와 left join fetch의 차이 (0) 2023.09.18 AWS S3를 이용한 사진 저장 (0) 2023.07.31 자바 코드로 정렬 vs db에서 특정 값을 정렬해서 select (0) 2023.07.28 비어있을 수도 있는 객체의 조회 -> Optional 사용 (0) 2023.07.27 @RequestParam과 @RequestBody의 차이점 (0) 2023.07.22