N+1 문제

SOL·2023년 3월 15일
0

spring

목록 보기
3/4

N+1 문제는 JPA와 hibernate에만 특정되는 문제는 아니고, data access technology 를 쓸 때 발생할 수 있는 문제

정의

parent entity를 받기 위한 쿼리 1개 + child entities를 받기 위한 쿼리 N개

  • 엔터티
@Entity
@Table
public class Post{
	
    @Id
    private Long id;
    
    private String content;
    
    @OneToMany(mappedBy = "post")
    private Set<Comment> comments;
}
@Entity
public class Comment{

	@Id
   	private Long id;
    
    private String content;
}

select * from post;

-> post를 select하고 각 record에 있는 post_id를 가지고 comment 테이블 가서 select을 또 한다.

N의 의미

parent table에서 select 된 수를 의미한다.

해결책

public interface PostRepository extends CrudRepository<Post, Long> {
	
    // 1. N+1 문제가 database level에서 발생
    List<Post> findAllBy();
}
  1. fetch join 사용해서 해결
@Query("SELECT p FROM Post p LEFT JOIN FETCH p.comments")
List<Post> findWithFetchJoin();
  1. EntityGraph 사용해서 해결 - 권장하지 않음
@EntityGraph(attributePaths = {"comments"})
List<Post> findAll();
  1. @BatchSize
@Entity
@Table
public class Post{
	
	...
    
    @OneToMany(mappedBy = "post")
    @BatchSize(size = 10)
    private Set<Comment> comments;
}

-> select * from comment where post_id in (?, ?, ?, ...) 이런 식으로 쿼리가 날라가서 n번 발생할 걸 n/batch_size 번 발생하게 하는 것이다.

  • application.yml 파일에서 bech size를 정할 수도있다.
spring.jpa.properties.hibernate.default_batch_fetch_size: 1000
  1. FetchMode.SUBSELECT
@Entity
@Table
public class Post{
	
	...
    
    @OneToMany(mappedBy = "post")
    @Fetch(FetchMode.SUBSELECT)
    private Set<Comment> comments;
}
  • 첫번째 쿼리
SELECT * from posts;
  • 두번째 쿼리
SELECT * from comments 
where post_id in (select id from posts);

-> complex한 쿼리일 경우 성능이 떨어진다. 따라서 filterpage 가 필요.., 딱 필요한 id만 두번째 쿼리에 넘겨져야 한다.

참고


0개의 댓글