≣ 목차
즉시로딩(Eager)
즉시로딩은 데이터를 조회할 때, 부모 엔티티를 가져올때 관련된 자식 엔티티도 함께 가져오는 방식으로 작동합니다.
추가적으로 @ManyToOne, @OneToOne의 fetch 속성에 기본값은 즉시로딩으로 설정되어 있으며, 즉시로딩을 사용하려면 아래와 같이 작성하면 됩니다.
@xxToxx(fetch = fetchType.EAGER)
즉시로딩 사용 시 간단한 로그
Hibernate:
select
member0_.MEMBER_ID as MEMBER_I1_0_0_,
member0_.TEAM_ID as TEAM_ID3_0_0_,
member0_.USERNAME as USERNAME2_0_0_,
team1_.TEAM_ID as TEAM_ID1_1_1_,
team1_.name as name2_1_1_
from
Member member0_
left outer join
Team team1_
on member0_.TEAM_ID=team1_.TEAM_ID
where
member0_.MEMBER_ID=?
지연로딩(Lazy)
지연 로딩은 즉시 로딩과 반대로 필요한 최소한의 엔티티만 가져오는 방식으로, 부모 엔티티를 조회할 때 자식 엔티티를 가져오지 않습니다. 대신 자식 엔티티에 접근하는 경우에는 추가적으로 필요한 쿼리를 실행하여 데이터를 가져옵니다. @OneToMany와 @ManyToMany는 기본적으로 지연 로딩을 사용하며, 지연 로딩을 사용하려면 아래와 같이 작성하면 사용할 수 있습니다.
@xxToxx(fetch = FetchType.LAZY)
지연로딩 사용 시 로그
Hibernate:
select
team0_.TEAM_ID as TEAM_ID1_1_0_,
team0_.name as name2_1_0_
from
Team team0_
where
team0_.TEAM_ID=?
그렇다면 어떤 전략을 사용하는게 더 좋을까??
결론만 말씀드리면 웬만하면 지연로딩을 사용하는게 더 좋습니다. 왜냐하면 즉시로딩을 사용하면 예상하지 못한 문제가 발생할 수 있습니다.
즉시로딩 사용 시 문제점
N+1 문제
N+1 문제는 데이터베이스에서 데이터를 조회할 때 성능 이슈로 한 개의 쿼리 조회 시 N개의 쿼리가 발생하는 문제입니다. 예를 들어, 다음과 같은 상황을 가정해 보겠습니다.
테이블 구조: Member 테이블이 있고, 하나의 Team에 여러 개의 사용자(Member)를 가질 수 있습니다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id")
Team team;
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String teamname;
}
상황: 모든 사용자를 조회 - 코드에서는 추가 쿼리 1개만 발생
try {
Team team = new Team();
team.setName("teamTest");
em.persist(team);
Member member = new Member();
member.setName("test");
member.setTeam(team);
em.persist(member);
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m", Member.class)
.getResultList();
tx.commit();
}
모든 Member를 조회하는 쿼리를 실행하면 처음에는 Member에 대한 데이터만 가져옵니다. 그러나 즉시로딩으로 설정된 설정된 Member와 Team 간의 관계 때문에 각 Member에 대해 연관된 Team 정보를 가져오기 위해 추가 쿼리가 발생하게 되어 총 N+1개의 쿼리가 실행됩니다.
예를 들어, 3개의 Team이 존재하고 5명의 Member가 있으면 처음에 1개의 쿼리로 모든 Member를 가져오고 그 다음 5명의 Member가 속했는데 3개의 Team에 대해 쿼리가 3개 추가 실행되어 총 1 + 3 = 4개의 쿼리가 실행됩니다. 이렇게 N+1문제로 추가적인 쿼리가 발생해 성능 저하가 발생합니다.
정리
첫 번째 쿼리: 한 번의 쿼리로 Member 조회
추가 쿼리 : 엔터티에 연관된 엔터티의 개수 만큼의 추가 쿼리를 수행
예상치 못한 조인 쿼리 생성
즉시로딩을 사용하면 한 개의 테이블에서 여러 테이블 간 조인을 사용할 때 성능 저하가 생길 수 있는데, 이는 즉시로딩이 연관된 모든 테이블을 한 번에 가져오는 방식이기 때문에 조인한 테이블의 수가 많아질수록 쿼리가 복잡해지기 때문입니다.
참조
https://woo-chang.tistory.com/28
https://sjh9708.tistory.com/160
'JAVA > JPA' 카테고리의 다른 글
[JPA] JPQL 간단 정리 및 기본 문법 (0) | 2024.11.25 |
---|---|
[Spring + Java] JPA 타입 정리 (0) | 2024.11.22 |
[JPA] JPA 프록시 정리 (0) | 2024.11.14 |
[Spring + JPA] JPA 상속관계 매핑 (0) | 2024.11.12 |
[Spring + JPA] Entity 연관 관계 매핑 - 관계 유형 (0) | 2024.11.08 |