코딩딩/Error

OneToOne 관계에서 N+1 문제가 발생하는 이유

전낙타 2024. 1. 4. 12:38

프로젝트를 진행하다가 OneToOne 관계에서 FetchType.LAZY를 설정해주었음에도 즉시 로딩이 실행되 N+1 문제가 발생하는것을 확인했다.

 

문제의 Entity들

@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Table(name = "review")
@Entity
@Builder
public class Review extends BaseEntity {

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE)
	private Long reviewSeq;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "hospital_seq")
	private Hospital hospital;

	@OneToOne(fetch = FetchType.LAZY, mappedBy = "review")
	private Appointment appointment;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "member_seq")
	private Member member;

	@Column(nullable = false)
	private int starRating;

	@Column(nullable = false)
	private String content;

}
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicInsert
@Getter
@Table(name = "appointment")
@Entity
@Builder
public class Appointment extends BaseEntity {

	@GeneratedValue(strategy = GenerationType.SEQUENCE)
	@Id
	private Long appointmentSeq;

	@JoinColumn(name = "member_seq")
	@ManyToOne(fetch = FetchType.LAZY)
	private Member member;

	@JoinColumn(name = "children_seq")
	@ManyToOne(fetch = FetchType.LAZY)
	private Children children;

	@JoinColumn(name = "doctor_seq")
	@ManyToOne(fetch = FetchType.LAZY)
	private Doctor doctor;

	@JoinColumn(name = "hospital_seq")
	@ManyToOne(fetch = FetchType.LAZY)
	private Hospital hospital;

	@OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "review_seq")
	private Review review;

	@Column(nullable = false)
	private LocalDateTime appointmentDate;

	@Column(nullable = false)
	private String appointmentHour;

	@Column(nullable = false)
	private String appointmentMinute;

	@ColumnDefault("'0'")
	private String status;

	@Column
	private String note;
}

 

 

문제의 Entity들의 관계를 살펴보면 Appointment가 연관관계의 주인인것을 확인할 수 있다.

 

여기서 fetch join을 사용해 조건에 맞는 entity를 조회해주는 Repository를 작성해주자

@Repository
public interface ReviewRepository extends JpaRepository<Review, Long> {

	@Query("select r from Review r"
		+ " join fetch r.member m"
		+ " join fetch r.hospital h"
		+ " where r.hospital.hospitalSeq = :hospitalSeq"
	)
	Page<Review> findAllWithMember(Pageable pageConfig, @Param("hospitalSeq") Long hospitalSeq);
}

 

Review와 Member, Hospital Entity까지 조회해오는 쿼리를 작성했다.

 

작성된 쿼리와 엔티티의 세팅값을 보면 Review와 Member, Hospital을 조회하는 쿼리만 나가야 정상이다.

 

하지만 작동된 쿼리를 살펴보면 호출하지 않은 Appointment까지 조회가 되는것을 볼 수 있다.

 

 

N+1 문제가 발생해버린것이다.

 

이를 해결하는 방법은 아주 간단하다.

단지 연관관관계의 주인을 바꿔주는 방법으로 해결이 가능하다.

 

N+1 문제가 발생하지 않고 한방쿼리로 해결된다.

 

이유는 해당 블로그를 참고하여 이해했다.

https://pooney.tistory.com/95

 

JPA - OneToOne관계 N+1문제

안녕하세요. 오늘은 JPA 작업을 하시면서 발생하는 양방향 OneToOne 관계에서 주인과 주인이아닌 LazyLoding(지연로딩)으로 설정 했지만 적용이 안되고 eagerLoding(즉시로딩)으로 조회해서 발생하는 흔

pooney.tistory.com


Enrity의 ID값을 직접 컬럼에 저장해줘 n+1 문제를 해결했다!
https://coding-camel.tistory.com/140