One Two Many fetch Join
페이징 페치 조인을 사용해 보았습니다. 이런 HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory 오류가 발생했습니다. 이 오류는 컬렉션 페치 조인에 적용된 상태에서 페이징을 적용할 때 발생하며, 이는 Hibernate가 컬렉션을 메모리에 로드한 후에 페이징을 적용해야 한다는 것을 의미합니다.
이러한 상황에서는 데이터가 적은 경우에는 큰 문제가 되지 않지만, 데이터가 많으면 성능 이슈가 발생할 수 있고, 때로는 메모리 초과 예외가 발생할 수도 있습니다. 이러한 이유로 Hibernate는 경고 메시지를 통해 알려줍니다
해결 방법
쿼리 수정
컬렉션 페치 조인 대신 필요한 데이터만 가져올 수 있는 쿼리를 작성해 페이징 처리에 대한 성능 문제를 해결할 수 있습니다.
@Repository
public interface ParentEntityRepository extends JpaRepository<ParentEntity, Long> {
// 컬렉션 페치 조인 대신 단순한 쿼리 사용
@Query("SELECT DISTINCT p FROM ParentEntity p")
Page<ParentEntity> findAllPaged(Pageable pageable);
}
서브 쿼리
필요한 데이터만을 가져오는 방법입니다.
주 쿼리와는 별도로 컬렉션을 가져오므로 페이징과 사용할 때 유용합니다.
@Fetch(FetchMode.SUBSELECT)
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<ChildEntity> children = new ArrayList<>();
BetchSize
BatchSize를 설정하여 일괄적으로 컬렉션을 가져오는 방법
오류를 피하기 위해 일괄적으로 가져올 때 한 번에 가져올 데이터 양을 제어할 수 있습니다.
@BatchSize(size = 10) // 적절한 배치 크기 설정
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<ChildEntity> children = new ArrayList<>();
지연 로딩 사용
컬렉션을 지연 로딩으로 설정하여, 필요한 시점에만 컬렉션을 로드합니다.
@Entity
public class ParentEntity {
// 이하 생략
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) // Lazy 로딩 설정
private List<ChildEntity> children = new ArrayList<>();
}
@Repository
public interface ParentEntityRepository extends JpaRepository<ParentEntity, Long> {
// 페이징 처리를 위한 쿼리
@Query("SELECT DISTINCT p FROM ParentEntity p")
Page<ParentEntity> findAllPaged(Pageable pageable);
}
페이징 컬렉션 로딩 전략
Hibernate에서 제공하는 페이징 컬렉션 로딩 전략을 사용하여 필요한 만큼의 데이터만 가져옵니다.
이런 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적이지만 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 한다면 페치조인보다는 여러 테이블에서 필요한 필드들만 조회해서 DTO 반환하는 것이 효과적일 수 있습니다.
'알쓸I잡(알면 쓸모있는 IT 잡학사전)' 카테고리의 다른 글
-parameters 플래그 Error (0) | 2024.08.24 |
---|---|
Intellij IDEA 로컬기록 (0) | 2024.02.09 |
서버 응답: "status":"BAD_REQUEST","msg":"Failed to convert value of type 'java.lang.String (0) | 2024.01.30 |