본문 바로가기

개발/Spring Boot

[Spring Boot] jpa n+1 문제

반응형

소개

N+1 문제는 데이터베이스 쿼리의 성능 이슈 중 하나로, 특히 Spring Data JPA와 같은 ORM(Object-Relational Mapping) 프레임워크를 사용할 때 발생할 수 있습니다.

이 문제는 관계형 데이터베이스에서 연관된 엔티티를 검색할 때 발생하며, 한 번의 쿼리로 필요한 데이터를 가져오지 않고 추가적인 쿼리를 여러 번 실행하는 상황을 말합니다.

예를 들어, 하나의 Post 엔티티와 여러 개의 Comment 엔티티가 있다고 가정해 봅시다.

예제


@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    private List<Comment> comments;

    // 다른 필드들...
}

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;

    // 다른 필드들...
}

그리고 PostRepository를 만들어서 findAll 메서드를 호출할 때 N+1 문제가 발생하도록 합니다

@Repository
public interface PostRepository extends JpaRepository<Post, Long> {

  List<Post> findAll();
}

이제 PostService에서 이 리포지토리를 사용하는 예제를 살펴봅니다.

@Service
public class PostService {
    @Autowired
    private PostRepository postRepository;

    @Transactional
    public List<Post> getAllPosts() {
        List<Post> posts = postRepository.findAll();

        // 여기에서 각각의 Post에 접근할 때마다 Comment를 가져오는 추가적인 쿼리가 발생함 (N+1 문제)
        for (Post post : posts) {
            List<Comment> comments = post.getComments();
            // comments를 사용하는 로직...
        }

        return posts;
    }
}

설명

위 코드에서 getAllPosts 메서드에서 postRepository.findAll()을 호출한 후에 각 Post에 대해 getComments()를 호출하면, 추가적인 쿼리가 발생하여 N+1 문제가 발생합니다. 이 경우, FetchType.LAZY로 설정된 comments 필드는 실제로 사용될 때 로딩이 되기 때문입니다.

해결법

N+1 문제를 해결하려면 JOIN FETCH 또는 @EntityGraph와 같은 방법을 사용하여 한 번의 쿼리로 필요한 데이터를 모두 가져오는 것이 좋습니다.

 

repository 객체에서 동작시킬 쿼리 위에 조인할 연관된 엔티티 설정하는 annotation들의 예제

 

EntityGraph 예제

  • @EntityGraph(attributePaths = "comments")

JOIN FETCH예제

  • @Query("SELECT DISTINCT p FROM Post p JOIN FETCH p.comments")

간단설명

쉽게 설명하여
N+1 문제는 쿼리 한번으로 동작해도 되는 작업을 FetchType.LAZY로 설정되어있는 연관된 엔티티가 있는경우 호출하면 호출한 시점에 쿼리를 동작시켜 성능 저하가 될 수 있다는 내용이다

반응형

'개발 > Spring Boot' 카테고리의 다른 글

[Spring Boot] JDBC Template이란?  (0) 2023.12.29
[Spring Boot] Mock MVC란?  (0) 2023.12.14
[Spring Boot] Spring에서 사용된 디자인 패턴  (0) 2023.12.05
[Spring Boot] Spring Batch란?  (0) 2023.11.23
[Spring Boot] Junit이란?  (0) 2023.11.20