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를 한 번의 쿼리로 가져옴.
주의사항
- 컬렉션 페치 조인
- 여러 컬렉션을 패치 조인하면 데이터 중복 문제가 발생할 수 있음.
- JPA는 이를 허용하지 않으며 예외 발생 가능.
- 페이징 사용 제한
- JOIN FETCH는 데이터 중복으로 인해 JPA가 페이징을 제대로 처리하지 못함.
- 해결 방법: Batch Fetching 사용.
- 연관 관계 관리
- 패치 조인은 성능을 위해 연관 데이터를 미리 가져오지만, 잘못 사용하면 오히려 불필요한 데이터 로드로 성능 저하.
'학습 기록 (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 |