• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

@ManyToOne FetchType=EAGER로 조회 시 N+1문제 발생

18.09.18 02:34 작성 조회수 154

1

안녕하세요 기선님

JPA 강좌 정말 잘 보고있습니다!

@ManyToOne 관계 매핑한 엔티티를 EAGER 타입으로 조회를 할때요

어떤 경우에는 조인으로 두 엔티티 정보를 한번에 쿼리하는 반면에,

각각의 엔티티를 따로 쿼리하는 경우가 있어서 EAGER 조회에서도 N+1문제가 발생하더라고요.

어떤 경우엔 조인이 되고 어떤 경우에 각각 쿼리가 발생하는지

알려주실 수 있을까요?

( 지금 껏 테스트로 추측하기로는 id 로 조회할 때는 조인 쿼리가 발생하고,

그외에는 별개 쿼리가발생하는 것 같아요)

코드랑 쿼리 결과도 첨부드릴게요

@Entity
public class Post {
    @Id @GeneratedValue
    private Long id;
    private String name;
    public Post() {}
    public Post(String name) {
        this.name = name;
    }
}

@Entity
public class Comment {
    @Id @GeneratedValue
    private Long id;
    private String title;
    @ManyToOne
    private Post post;
    public Comment() {}
    public Comment(String title, Post post) {
        this.title = title;
        this.post = post;
    }
}
@Component
public class JpaRunner implements ApplicationRunner {
    @Autowired
    PostRepository postRepository;
    @Autowired
    CommentRepository commentRepository;

    @Transactional
    @Override
    public void run(ApplicationArguments args) {
        //아래 데이터가 입력된 상황
//        Post post1 = new Post("A");
//        Post post2 = new Post("B");
//        Post post3 = new Post("C");
//        postRepository.saveAll(Arrays.asList(post1, post2, post3));
//        postRepository.flush();
//
//        Comment comment1 = new Comment("a", post1);
//        Comment comment2 = new Comment("a", post2);
//        Comment comment3 = new Comment("a", post3);
//
//        commentRepository.saveAll(Arrays.asList(comment1, comment2, comment3));
//        commentRepository.flush();

        commentRepository.findById(1L);
        commentRepository.findByTitle("a");
    }
}

실행된 쿼리

Hibernate: 
    select
        comment0_.id as id1_0_0_,
        comment0_.post_id as post_id3_0_0_,
        comment0_.title as title2_0_0_,
        post1_.id as id1_1_1_,
        post1_.name as name2_1_1_ 
    from
        comment comment0_ 
    left outer join
        post post1_ 
            on comment0_.post_id=post1_.id 
    where
        comment0_.id=?
2018-09-18 02:32:41.805  INFO 5078 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: 
    select
        comment0_.id as id1_0_,
        comment0_.post_id as post_id3_0_,
        comment0_.title as title2_0_ 
    from
        comment comment0_ 
    where
        comment0_.title=?
Hibernate: 
    select
        post0_.id as id1_1_0_,
        post0_.name as name2_1_0_ 
    from
        post post0_ 
    where
        post0_.id=?
Hibernate: 
    select
        post0_.id as id1_1_0_,
        post0_.name as name2_1_0_ 
    from
        post post0_ 
    where
        post0_.id=?
Hibernate: 
    select
        post0_.id as id1_1_0_,
        post0_.name as name2_1_0_ 
    from
        post post0_ 
    where
        post0_.id=?

답변 1

답변을 작성해보세요.

1

좋은 질문 주셔서 감사합니다. 추측하신대로 id로 조회하는 것을 제외하고 기본 패치 모드가 적용되지 않습니다. 따라서 그 부분은 직접 컨트롤 해주시는게 좋습니다. 가령, 뒤에서 학습하실 EntityGraph라는 기능을 사용해서 해당 findByTitle도 Post 데이터를 eager 패치할 수 있습니다.

@EntityGraph(attributePaths = "post")

List<Comment> findByTitle(String title);

이렇게 코드랑 로그까지 올려주신 성의에 다시 한번 감사드립니다.