오늘은 스터디를 하던 중에, 팀원분이 JPA 데이터 뻥튀기에 대해 언급을 해주셨습니다. 일대다 관계에서 페치 조인을 실행하면 데이터가 뻥튀기 되는 현상이 있다라는 내용을 공유해주셔서, 그부분에 대한 궁금증을 정리해보려고 합니다.
1. 페치 조인 vs 일반 조인
먼저 페치 조인이 무엇인지 알아보고, 일반 조인과는 어떤 차이점이 있는지에 대해서 알아볼 필요가 있습니다. 페치 조인이란, JPQL에서 성능 최적화를 위해 제공하는 기능으로써, 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능입니다. 지연 로딩이 아닌, 즉시 로딩을 통해 데이터를 가져오는데, 예를 들어 Order 앤티티와, OrderItem 앤티티가 일대다인 상황에서 Order를 조회할 때, 반드시 orderItem도 함께 조회를 해야하는 비즈니스 로직이라면 페치 조인을 사용해서 호출하면 전부 가져올 수 있습니다.
일반 조인과의 차이점으로는 일반 조인의 경우, 연관된 엔티티를 함께 조회하지 않으며, JPQL은 결과를 반환할 때, 연관관계를 고려하지 않고, 단지 select 절에 지정한 엔티티만 조회합니다.
2. 컬렉션 페치 조인(데이터 뻥튀기)
일대다 관계에서 컬렉션 페치 조인을 호출을 하게 되면 데이터 뻥튀기가 발생하게 됩니다. 추가로 컬렉션 페치 조인은 페이징 처리가 불가능합니다. 왜냐하면 페이징 처리를 하기 위해서는 전체 데이터를 먼저 가져와야 되는데, 컬렉션 페치 조인은 데이터를 미리 가져오기 때문이죠. 그렇다면 이러한 데이터 뻥튀기를 해결 할 수 있는 방법에는 어떤 것이 있을까요?
첫번째는 DISTINCT(중복 제거)를 사용하는 것입니다. 데이터가 뻥튀기, 즉 중복돼서 노출되는 데이터를 제거할 수 있기 때문에, 중복된 결과를 제거한다는 점 자체에서 이점을 발휘합니다. 하지만 이러한 중복 제거를 진행을 해도, 여전히 전체 데이터를 가져오기 때문에, 페이징 처리를 할 수가 없다는 단점이 있습니다.
데이터 뻥튀기와 페이징 처리 불가를 해결하기 위해서도 역시, 여러가지 방법이 있습니다. 첫번째로는 @BatchSize 어노테이션을 사용하는 방법입니다. 보이시는 것처럼 members에 배치사이즈 어노테이션을 선언하고 SIZE를 지정해주면 해당 개수만큼 데이터를 가져올 수 있습니다. 아래 코드에서는 setFirstResult와 setMaxResults를 사용하여 페이징 처리를 해주면 됩니다.
@Entity
public class Team {
@Id
private Long id;
@OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
@BatchSize(size = 100)
private List<Member> members; //
getters, setters, constructors
}
public List<Team> findAllTeams(int pageIndex, int pageSize) {
TypedQuery<Team> query = em.createQuery("SELECT t FROM Team t", Team.class);
query.setFirstResult(pageIndex * pageSize);
query.setMaxResults(pageSize);
List<Team> teams = query.getResultList();
for (Team team : teams) {
team.getMembers().size(); // 각 Team 엔티티에 대한 Member 엔티티 조회
}
return teams;
}
'IT' 카테고리의 다른 글
비대면바우처플랫폼, 추천서비스 TOP3(23년 최신) (0) | 2023.03.30 |
---|---|
JSON, JsonObject, JsonArray의 차이 (0) | 2023.03.23 |
코틀린에서 reified를 사용하는 이유 (0) | 2023.03.13 |
Jackson ObjectMapper란? (0) | 2023.03.08 |
엘지 유플러스 공유기 PC 원격 실행 설정 방법(윈도우10, won)(23년 최신) (0) | 2023.03.06 |
댓글