본문 바로가기

학습 기록 (Learning Logs)/CS Study

Fetch Join

 

 


db에서의 join 에 없는 Fetch join

 

 


 

fetch join

객체지향-- 관계형 db의 차이를 보완하기위해 제공되는 기능

SQL 기반의 조인은 관계형 데이터를 조인

패치 조인연관된 엔티티 데이터를 한 번의 쿼리로 가져와 메모리에 로드

 

 

 


 

  • SQL 조인: 단순히 데이터를 조합해서 결과를 반환.
SELECT *
FROM orders o
JOIN customers c ON o.customer_id = c.id;

 

 

  • 패치 조인: SQL로 조합한 데이터를 JPA가 객체 그래프로 변환하여 메모리에 저장.

결과: Order와 Customer 엔티티가 객체로 매핑되고, 연관 관계가 완전한 객체 그래프로 로드.

String jpql = "SELECT o FROM Order o JOIN FETCH o.customer";
List<Order> orders = em.createQuery(jpql, Order.class).getResultList();

 

 


 

 

 

SQL 조인 유형

INNER JOIN

 

  • 두 테이블에서 조건이 일치하는 데이터만 가져옴.
  • 조건을 만족하지 않는 데이터는 제외.
  • 가장 기본적이고 자주 사용되는 조인.

 

LEFT OUTER JOIN (LEFT JOIN)

  • 왼쪽 테이블의 모든 데이터를 가져오고, 오른쪽 테이블에서 일치하는 데이터가 없으면 NULL로 반환.
 

RIGHT OUTER JOIN (RIGHT JOIN)

  • 오른쪽 테이블의 모든 데이터를 가져오고, 왼쪽 테이블에서 일치하는 데이터가 없으면 NULL로 반환.
 

FULL OUTER JOIN

 

  • 양쪽 테이블의 데이터를 모두 가져옴.
  • 일치하지 않는 데이터는 NULL로 채워짐.

 

SELF JOIN

 

  • 같은 테이블을 기준으로 스스로를 조인.
  • 주로 계층 구조 데이터를 처리할 때 사용.

 

CROSS JOIN

 

  • 두 테이블의 **데카르트 곱(Cartesian Product)**를 반환.
  • 조건이 없을 경우 모든 조합이 결과로 나타남.

 


JPA/QueryDSL의 추가적인 조인 방식

 

(1) FETCH JOIN (패치 조인)

  • 연관 엔티티 그래프 로드
  • SQL 조인과 달리 메모리에 객체 그래프를 로드하는 데 초점.
  • SQL 조인처럼 데이터를 가져오되, 연관 엔티티를 한 번의 쿼리로 즉시 로드하는 방식.

(2) ENTITY JOIN

 

  • 비연관 엔티티 간 조인
  • JPA에서 엔티티 간 관계가 명시적으로 매핑되어 있지 않더라도 ON 절을 사용하여 두 엔티티를 조인.
  • 보통 복잡한 조인 조건을 처리할 때 유용.
String jpql = "SELECT o FROM Order o JOIN Customer c ON o.customerName = c.name";
List<Order> orders = em.createQuery(jpql, Order.class).getResultList();

 

 

(3) SUBQUERY JOIN

 

  • JPA에서 서브쿼리를 조인에 사용 가능.
  • 복잡한 데이터 조건을 만족할 때 사용.
String jpql = "SELECT o FROM Order o WHERE o.amount > (SELECT AVG(o2.amount) FROM Order o2)";
List<Order> orders = em.createQuery(jpql, Order.class).getResultList();

 

 

(4) SET-BASED JOINS

  • SQL에서 UNION이나 INTERSECT와 같은 집합 연산자를 활용해 조인처럼 사용할 수 있음.
-- 예: 두 테이블에서 중복되지 않는 데이터 가져오기
SELECT column_name FROM table1
EXCEPT
SELECT column_name FROM table2;

 

 


SQL 확장 조인 (Window Function)

SQL에서는 조인을 확장하거나 대체할 수 있는 기능들도 제공하며, JPA로 완벽히 구현되지 않을 수도 있습니다.

(1) LATERAL JOIN

  • 서브쿼리를 참조하여 행별로 동적으로 계산.
SELECT o.*, c.*
FROM orders o
LEFT JOIN LATERAL (
  SELECT * FROM customers c WHERE c.customer_id = o.customer_id
) c ON TRUE;

(2) WINDOW FUNCTION 조인

  • 윈도우 함수(ROW_NUMBER, RANK, DENSE_RANK 등)를 활용하여 특정 조건에 맞는 데이터를 조인.
SELECT *
FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY created_at DESC) AS rank
  FROM products
) ranked_products
WHERE rank = 1;

 

NoSQL의 조인(비전통적 조인)

관계형 데이터베이스가 아닌 NoSQL에서도 특정 방식으로 조인처럼 데이터를 결합할 수 있습니다.

(1) MongoDB Lookup

  • MongoDB의 $lookup 기능은 조인과 비슷한 역할.
db.orders.aggregate([
  {
    $lookup: {
      from: "customers",
      localField: "customer_id",
      foreignField: "_id",
      as: "customer_info"
    }
  }
])

 

 


 

패치 조인의 장점

 

  • N+1 문제 해결: 연관 데이터를 미리 로드하여 다수의 쿼리 실행을 방지.
  • 데이터베이스 접근 횟수를 줄여 성능 개선.

N+1 문제 예시:

  • Order와 Customer가 1:N 관계인 경우.
  • @OneToMany(fetch = FetchType.LAZY)일 때, orders를 조회한 후 각 Order마다 추가로 Customer를 조회(N번 쿼리).
String jpql = "SELECT o FROM Order o JOIN FETCH o.customer";
List<Order> orders = em.createQuery(jpql, Order.class).getResultList();

 

→ Order와 Customer를 한 번의 쿼리로 가져옴.

 


주의사항

  1. 컬렉션 페치 조인
    • 여러 컬렉션을 패치 조인하면 데이터 중복 문제가 발생할 수 있음.
    • JPA는 이를 허용하지 않으며 예외 발생 가능.
  2. 페이징 사용 제한
    • JOIN FETCH는 데이터 중복으로 인해 JPA가 페이징을 제대로 처리하지 못함.
    • 해결 방법: Batch Fetching 사용.
  3. 연관 관계 관리
    • 패치 조인은 성능을 위해 연관 데이터를 미리 가져오지만, 잘못 사용하면 오히려 불필요한 데이터 로드로 성능 저하.

'학습 기록 (Learning Logs) > CS Study' 카테고리의 다른 글

[Note]redis  (0) 2024.12.16
[Note]In-memory cache-basic  (0) 2024.12.16
JPA-troubleShooting  (0) 2024.12.12
JPA-advanced-question  (0) 2024.12.12
JPA-optimized-performance  (0) 2024.12.12