반응형
1. N + 1 문제란?
N+1 문제는 하나의 쿼리(1)로 N개의 결과를 가져온 후, 각 결과마다 추가 쿼리(N)가 실행되는 상황을 말한다.
예를 들어서, Member가 100명이면
- members 조회 쿼리: 1번
- 각 member가 가진 Post 조회 쿼리: 100번
- 총 101번의 쿼리 발생 → 이것이 N+1 문제
2. MyBatis에서 발생하는 N+1 문제
public class Member {
private Long id;
private String name;
private int age;
private List<Post> posts; // 나중에 수동으로 채움
}
public class Post {
private Long id;
private String name;
private Long memberId;
}
public interface MemberMapper {
List<Member> findAll(); // 전체 회원 조회
}
public interface PostMapper {
List<Post> findByMemberId(Long memberId); // 특정 회원의 게시글 조회
}
List<Member> members = memberMapper.findAll(); // 쿼리 1번
for (Member member : members) {
List<Post> posts = postMapper.findByMemberId(member.getId()); // 쿼리 N번
member.setPosts(posts);
}
MyBatis에선 이러한 N+1문제를 방지하기 위해서
<select id="findAllMembersWithPosts" resultMap="memberWithPostsMap">
SELECT
m.id AS m_id, m.name AS m_name, m.age AS m_age,
p.id AS p_id, p.name AS p_name, p.member_id AS p_member_id
FROM member m
LEFT JOIN post p ON m.id = p.member_id
</select>
ResultMap으로 조인해서 한번에 가져온다 → 쿼리 1번에 List<Post> 로드
3. JPA에서의 연관관계 매핑방식
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
private int age;
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY) // 핵심!
private List<Post> posts = new ArrayList<>();
}
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
}
그런데 JPA는 객체 간의 관계를 명시적으로 매핑하고, 이를 기준으로 자동으로 데이터를 로딩한다.
따라서 List<Post> 는 별도의 쿼리를 날리지 않아도 @OneToMany 연관관계 매핑을 통해 자동으로 로딩된다.
만약 member.getPosts()를 호출한다면?
- fetch = LAZY인 경우 → 그 시점에 SQL 쿼리 날려서 가져옴
- fetch = EAGER인 경우 → member를 가져올 때 post도 함께 가져옴
4. 결론
항상 모든 것을 다 해주는 JPA만 사용하다가, 직접 쿼리를 조작하는 MyBatis를 사용하며
N+1문제에 대해서 체감하게 되었다...
고대의 프로그래밍 기술로 올라갈 수록 배울 것이 많아 좋다 :>
반응형
'Programming > TWIL' 카테고리의 다른 글
다이나모 DB에 대하여 (0) | 2025.04.13 |
---|---|
[TWIL] DB JOIN 으로 인한 중복 증가 현상에 대하여 (0) | 2025.04.06 |
[TWIL] 스프링 시큐리티 딥다이브 (0) | 2025.03.16 |
[TWIL] 왜 내가 설정한 로깅은 오락가락할까? 스프링 AOP와 프록시에 대하여 (3) | 2025.03.08 |
[TWIL] 웹 어플리케이션 아키텍처의 기초 (EC2/WAS/DOCKER) (0) | 2025.02.16 |