oguri's garage

JPA에서 DISTINCT가 필요한 경우와 필요하지 않은 경우 본문

개발하다/Spring

JPA에서 DISTINCT가 필요한 경우와 필요하지 않은 경우

oguri 2025. 10. 18. 23:36

상황

프로젝트에서 JOIN FETCH 쿼리를 작성했는데, 어떤 코드는 DISTINCT가 필요하고 어떤 코드는 필요하지 않다고 해서 해당 상황을 정리해보았다.

내가 작성한 코드:

@Query("SELECT om FROM OrderMember om " +
       "JOIN FETCH om.member " +
       "WHERE om.orderId = :orderId")
List<OrderMember> findByOrderIdWithMember(
    @Param("orderId") Long orderId
);

 

 

 


핵심: 조회 방향이 중요하다

1. ManyToOne 조회 (DISTINCT 불필요)

중간 테이블에서 연관 엔티티를 조회할 때는 각 행이 서로 다른 객체다.

@Entity
public class OrderMember {  // 이 엔티티를 조회
    @ManyToOne
    private Member member;
}


데이터:

orderId | memberId
-------------------
1       | 101
1       | 102
1       | 103


결과:

// 3개의 서로 다른 객체 → 중복 없음!
[
    OrderMember(1, 101),
    OrderMember(1, 102),
    OrderMember(1, 103)
]

 

 

 

2. OneToMany 조회 (DISTINCT 필요)

반대로 조회하면 부모 객체가 중복된다.

@Entity
public class Order {  // 이 엔티티를 조회
    @OneToMany
    private List<OrderMember> orderMembers;
}

@Query("SELECT o FROM Order o " +
       "JOIN FETCH o.orderMembers " +
       "WHERE o.orderId = :orderId")

 

문제:

// Order 객체가 3번 중복됨!
[
    Order@1001,  // orderId=1
    Order@1002,  // orderId=1 (중복!)
    Order@1003   // orderId=1 (중복!)
]

 

해결:

@Query("SELECT DISTINCT o FROM Order o " +
       "JOIN FETCH o.orderMembers " +
       "WHERE o.orderId = :orderId")

 

 

 




한눈에 보는 비교표

조회 방향 반환 타입 DISTINCT 이유
N → 1 (ManyToOne) List<중간테이블> 불필요 각 레코드가 다름
1 → N (OneToMany) List<부모엔티티> 필요 부모가 자식 수만큼 중복

 

 

 

 




결론

내 코드는 ManyToOne 방향으로 중간 테이블을 조회하므로 DISTINCT가 필요 없다.

  • 각 행이 서로 다른 (orderId, memberId) 조합
  • 중복 발생하지 않음
  • DISTINCT를 추가하면 오히려 불필요한 메모리 연산만 발생