JPA를 사용하다 보면 N+1 문제를 직면하는 일이 많다.
N+1 문제란 예를 들어 친구 목록을 가져오는데 각각 친구들의 상태 메시지는 다른 테이블에서 가져온다고 가정하면 두 테이블을 한 번에 가져오지 않았을 때 쿼리는 두 번 나가게 될 것이고 친구들 전체를 가져오게 된다면 N+1로 쿼리 수가 상당히 많아질 것이다.
즉, 추가적인 쿼리를 계속 보내는 것이다.
따라서 이러한 다수의 쿼리를 보내는 것을 방지하기 위해 한 번에 가져와야 하는데 그때 쓰이는 방법은
JPA에서는 @EntityGraph이고, QueryDSL에서는 .fetchJoin을 해주면 된다.
JPA(EntityGraph)
@Override
@EntityGraph(attributePaths = {"userCar", "account", "address"})
Optional<Rent> findById(Long id);
일단 RENT라는 테이블에는 USER_CAR, ACCOUNT, ADDRESS 테이블과 연관되어 있다.
그래서 위와 같이 조회할 때 EntityGraph에서 attributePaths에서 같이 가져올 변수명을 기입해 주면 된다.
그러면 N+1 문제를 방지할 수 있다.
QueryDSL(fetchJoin)
@Override
public Optional<Rent> findByRentAccountIdAndStatusOrStatus(Long rentAccountId, Status status1, Status status2) {
Rent findRent = jpaQueryFactory.selectFrom(QRent.rent)
.leftJoin(QRent.rent.review, review)
.fetchJoin()
.leftJoin(QRent.rent.account, account)
.fetchJoin()
.leftJoin(QRent.rent.rentAccount, account)
.fetchJoin()
.leftJoin(QRent.rent.address, address)
.fetchJoin()
.leftJoin(QRent.rent.userCar, userCar)
.fetchJoin()
.where(QRent.rent.rentAccount.id.eq(rentAccountId), QRent.rent.status.in(status1, status2)).fetchOne();
return Optional.ofNullable(findRent);
}
fetchJoin 같은 경우에는 보이는 것처럼 leftJoin을 해준 후에 fetchJoin만 해주면 연관된 객체를 한 번에 가져온다.
'JAVA > JPA' 카테고리의 다른 글
[JPA] Auditing을 사용해 등록일, 수정일, 등록자, 수정자 기록 남기기 (0) | 2023.01.03 |
---|---|
[JPA] 스프링 데이터 JPA로 벌크성 수정 쿼리 날려보기 (0) | 2023.01.02 |
[JPA] 스프링 데이터 JPA 페이징과 정렬 (feat. DTO를 사용해야 하는 이유) (0) | 2023.01.02 |
[JPA/JPQL] 페치 조인(fetch join)이란? 특징과 한계 - 엔티티 페치 조인, 컬렉션 페치 조인, DISTINCT로 중복 제거 (0) | 2022.12.29 |
[JPA] @MappedSuperclass로 공통 칼럼 상속받기 (0) | 2022.12.23 |