Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- 엘라스틱서치
- 자동화워크플로우
- 부트캠프
- 오버로딩
- jwt토큰
- 오블완
- STOMP
- 메소드
- 하이브리드접근법
- 자바
- 티스토리챌린지
- n8n
- springboot
- Kafka
- 헥사고날아키텍처
- 한화시스템부트캠프
- nplus1
- 캐시의 작동 원리
- QA
- 자료구조
- 테스트케이스
- JPA
- 프로토콜역할
- selenium
- kafka배포
- 스프링시큐리티
- XSS
- N+1문제
- Java
- 프로세스와스레드의차이
Archives
- Today
- Total
아쿠의 개발 일지
JPA 성능 최적화를 위한 fetch join과 EntityGraph 활용 본문
JPA를 사용하면서 연관 관계가 설정된 엔티티를 조회할 때 N+1 문제를 경험한 적이 있을 것입니다. 이는 하나의 쿼리를 실행한 후, 연관된 엔티티를 개별적으로 추가 조회하는 문제로 인해 성능 저하를 초래합니다. 이를 해결하기 위한 대표적인 방법이 fetch join과 EntityGraph입니다.
이번 글에서는 fetch join과 EntityGraph의 개념을 이해하고, 이를 활용하여 성능 최적화를 어떻게 할 수 있는지 알아보겠습니다. .👍😊
1. Fetch Join 소개 및 활용
Fetch Join 개념
fetch join은 JPA의 JOIN FETCH 키워드를 활용하여 연관된 엔티티를 한 번의 쿼리로 조회하는 방법입니다. 이를 통해 N+1 문제를 해결하고 불필요한 추가 조회를 방지할 수 있습니다.
Fetch Join 예제
@Entity
public class ChatRoom {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "chatRoom", fetch = FetchType.LAZY)
private List<ChatParticipation> participants;
}
@Entity
public class ChatParticipation {
@Id @GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private ChatRoom chatRoom;
@ManyToOne(fetch = FetchType.LAZY)
private User user;
}
기본적으로 ChatRoom과 ChatParticipation은 LAZY 전략을 사용하여 필요할 때 조회되지만, 아래와 같이 fetch join을 사용하면 한 번의 쿼리로 조회할 수 있습니다.
@Query("SELECT c FROM ChatRoom c JOIN FETCH c.participants WHERE c.id = :chatRoomId")
List<ChatRoom> findChatRoomWithParticipants(@Param("chatRoomId") Long chatRoomId);
쿼리 실행 결과 (하나의 SQL로 조회)
SELECT c.*, p.* FROM chat_room c
JOIN chat_participation p ON c.id = p.chat_room_id
WHERE c.id = ?
Fetch Join의 주의할 점
- 다중 fetch join 제한: JPA에서는 두 개 이상의 fetch join을 사용할 경우 오류가 발생할 수 있음
- 페이징 문제: fetch join이 포함된 쿼리는 setFirstResult() 및 setMaxResults()와 함께 사용할 수 없음
2. EntityGraph 소개 및 활용
EntityGraph 개념
EntityGraph는 JPA의 기능으로, 엔티티를 조회할 때 특정 연관 관계를 한 번에 가져올 수 있도록 설정하는 방법입니다. JPQL을 직접 작성하지 않아도 된다는 점이 fetch join과의 차이점입니다.
EntityGraph 예제
@Entity
@NamedEntityGraph(
name = "ChatRoom.withParticipants",
attributeNodes = @NamedAttributeNode("participants")
)
public class ChatRoom {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "chatRoom", fetch = FetchType.LAZY)
private List<ChatParticipation> participants;
}
@EntityGraph(value = "ChatRoom.withParticipants", type = EntityGraphType.LOAD)
@Query("SELECT c FROM ChatRoom c WHERE c.id = :chatRoomId")
List<ChatRoom> findChatRoomWithEntityGraph(@Param("chatRoomId") Long chatRoomId);
쿼리 실행 결과 (한 번의 SQL로 조회)
SELECT c.*, p.* FROM chat_room c
LEFT JOIN chat_participation p ON c.id = p.chat_room_id
WHERE c.id = ?
EntityGraph의 장점
- JPQL 없이 간결한 코드
- 다중 관계도 효율적으로 조회 가능
- 페이징과 함께 사용 가능
3. Fetch Join vs EntityGraph 비교
항목 | Fetch Join | EntityGraph |
JPQL 사용 여부 | 필요함 | 불필요함 |
다중 조인 지원 | 제한적 | 가능 |
페이징과의 호환성 | 불가능 | 가능 |
코드 가독성 | 중간 | 높음 |
언제 Fetch Join을 사용할까?
- 즉시 필요한 연관 엔티티를 가져와야 할 때
- JPQL 기반의 동적 쿼리가 필요한 경우
언제 EntityGraph를 사용할까?
- 기존 JPA 메서드 (findById, findAll 등)와 함께 사용하고 싶을 때
- 페이징을 적용하면서 연관 데이터를 조회해야 할 때
JPA에서 연관 관계를 조회할 때 fetch join과 EntityGraph를 적절히 활용하면 성능 최적화를 할 수 있습니다.
✔ 정리
- fetch join은 JPQL을 직접 사용하여 즉시 로딩할 때 유용하지만, 페이징에는 적합하지 않음
- EntityGraph는 JPA의 기본 메서드와 함께 사용할 수 있어 가독성이 높고 페이징도 지원
- 상황에 맞게 두 가지 방법을 적절히 조합하여 사용하면 최적의 성능을 확보할 수 있음
📌 프로젝트에 맞는 최적화 전략을 선택하여 성능을 개선해보세요! 🚀
728x90
'Programming > Java' 카테고리의 다른 글
[SpringBoot] 멀티쓰레드 환경에서의 동시성 제어 (Synchronized vs Lock vs Atomic) (0) | 2025.02.10 |
---|---|
[SpringBoot] S3 파일 업로드와 최적화 방법 (1) | 2025.01.31 |
[DevOps] Kubernetes로 채팅을 위한 Kafka와 Zookeeper 배포하기 (0) | 2025.01.09 |
[N8N] AI와 N8N (0) | 2025.01.06 |
[Java] 객체지향의 핵심 개념 & Spring Boot란? (0) | 2024.12.29 |