문제 상황
Post와 Comment가 일대다(1:N) 관계이고, Comment에서 @ManyToOne로 Post를 참조하고 있다.
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
private Post post;
}
특정 Post에 해당하는 Comment들을 찾고자 할 경우 findByPost나 findByPostId를 사용할 수 있을 것이다.
findByPost와 findByPostId의 쿼리가 동일할 것으로 기대되나 그렇지 않다.
findByPost는 post_id를 이용해서 WHERE 절로 찾으나, findByPostId는 Post와 LEFT JOIN후 post_id를 이용해서 WHERE 절로 찾는다. 다음의 실행 결과를 확인해보자.
이렇게 findByXxxId를 사용하면 불필요한 JOIN이 발생하여 비효율적인데 그 이유가 무엇일까?
findByPostId를 예로 들 때, post_id라는 외래 키를 가지고 조회하는 것이 아닌 Post의 식별자를 가지고 조회하는 것이다.
공식 문서에 따르면 쿼리 메서드 기능은 메서드 네이밍을 분석할 때 엔티티의 프로퍼티, 즉 필드만 참조할 수 있다고 되어 있다.
그렇기 때문에 post_id를 참조할 수 없고, Post의 식별자를 참조할 수 있기 때문에 LEFT JOIN 후 WHERE 절로 처리한다.
해결방법
메서드 명을 그대로 하고 JOIN없이 WHERE 절만으로 처리하고 싶다면, @Query를 사용하는 방법이 있다.
@Query("select c from Comment c where c.post.id = :postId")
List<Comment> findByPostId(@Param("postId") Long postId);
주의 사항
- ⚠️ 스프링 부트 3.2.6(hibernate-core 6.4.8.Final)까지 findByPostId는 left join 후 where 절로 처리한다.
- ⚠️ 스프링 부트 3.2.7(hibernate-core 6.4.9.Final)부터 findByPostId는 left join 없이 where 절로 처리한다.
참고 자료
'웹 백엔드' 카테고리의 다른 글
무중단 배포(블루/그린 배포)로 서비스 중단 없이 배포하기 (0) | 2025.01.09 |
---|---|
Git Submodule(서브모듈)을 통해서 Spring 설정(yml) 관리하기 (0) | 2025.01.05 |
Flyway를 통한 데이터베이스 마이그레이션을 알아보자 (1) | 2025.01.03 |
@JsonTypeInfo와 @JsonSubTypes를 활용하여 요청 데이터에 다형성을 적용해 보자 (1) | 2024.12.25 |
Spring JPA를 사용할 때, OneToMany에서 Fetch Join 사용 시 문제점을 알아보자 (0) | 2024.12.23 |