-
N + 1 정복하기 <5. Entity Graph>프레임워크/Spring Boot 2024. 2. 21. 13:27
시리즈1. https://iwsaitw.tistory.com/entry/N-1-정복하기
시리즈2. https://iwsaitw.tistory.com/entry/N-1-정복하기-2-FetchTypeEAGER
시리즈3. https://iwsaitw.tistory.com/entry/N-1-정복하기-3-Fetch-Join
시리즈4. https://iwsaitw.tistory.com/entry/N-1-정복하기-4-BatchSize
(소스코드: https://github.com/blog-example/-JPA-N_Plus_1)
ORM을 사용하면 만나는 흔한 이슈 중 하나인 N + 1 !
명확하게 설명할 수 있을 정도로 머리속에 집어넣어보겠습니다.
이번 글에서는 Entity Graph를 활용해서 N + 1을 해결하는 과정을 살펴보겠습니다.
1. Entity Graph가 무엇인가?
개발자가 조금 더 세밀하게 데이터 로딩전략을 수행할 수 있도록 만들어주는 기능이라고 합니다.
크게 Named Entity Graph 방법과 Dynamic Entity Graph 방법이 있습니다.
2. Named Entity Graph의 사용 방법
Named Entity Graph는 엔티티에 미리 데이터 fetching 방법에 대해서 정의해두고 사용처에서 가져다 쓰는 것에 의의가 있습니다.
또 서로 다른 전략을 가진 Graph를 정의해두고 골라서 사용할 수 있다는 장점도 있습니다.
엔티티에 NamedEntityGraph를 사용해서 Graph를 정의해줍니다.
@NamedEntityGraph( name = "post-with-comments", // 이 Graph를 가리키는 id attributeNodes = @NamedAttributeNode("comments") // 연관관계가 있는 필드 ) @Getter @NoArgsConstructor @Entity @Table(name = "posts") public class Post { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "post_id") private long postId; @Column(name = "title") private String title; @Column(name = "content") private String content; @OneToMany(mappedBy = "post") private List<Comment> comments = new ArrayList<>(); public void addComment(Comment comment) { if (!comments.contains(comment)) { comments.add(comment); comment.addPost(this); } } }
레포지토리에서 원하는 메소드 위에 @EntityGraph를 추가하고 사전에 정의한 Graph의 name을 연결해줍니다.
public interface PostRepository extends JpaRepository<Post, Long> { @EntityGraph(value = "post-with-comments") // 사용할 Graph의 이름 적용 List<Post> findAll(); }
간단하게 N + 1이 해결되는 것을 확인할 수 있습니다.
3. 동적으로 Entity Graph 적용
위에서는 미리 EntityGraph를 선언해 두고 가져다 사용하였다면, 이번에는 필요한 시점에 동적으로 EntityGraph를 생성해서 사용합니다.
public List<PostDto> getPosts() { EntityGraph<Post> graph = entityManager.createEntityGraph(Post.class); graph.addSubgraph(("comments")); List<Post> posts = entityManager.createQuery("SELECT p FROM Post p", Post.class) .setHint("javax.persistence.loadgraph", graph) .getResultList();
좀 더 복잡한 로직을 다룰 때 사용할 수 있을 것 같습니다.
이 글을 마지막으로 N + 1에 대한 글을 마무리 하겠습니다.
1번의 조회 쿼리 이후 관련된 데이터를 가져오면서 N 개의 쿼리가 추가로 발생하게 되는 N + 1에 대해서 알아보고
다양한 해결방법을 살펴보았습니다.
감사합니다.
참고
'프레임워크 > Spring Boot' 카테고리의 다른 글
RestTemplate은 4xx를 예외로 처리한다. (0) 2024.05.02 SpringBootApplication이 필요한 bean을 찾지 못하는 경우 (0) 2024.04.25 N + 1 정복하기 <4. @BatchSize> (0) 2024.02.21 N + 1 정복하기 <3. Fetch Join> (0) 2024.02.21 N + 1 정복하기 <2. FetchType.EAGER> (0) 2024.02.20