트러블 슈팅
N+1 문제 해결
yougeun
2022. 9. 14. 01:25
728x90
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Request extends Timestamped {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "REQUEST_ID")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "POST_ID")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "USER_ID")
private User user;
@Enumerated(value = EnumType.STRING)
@Column(nullable = false)
private RequestStatus requestStatus;
public Request(Post post,User user){
this.post = post;
this.user = user;
this.requestStatus = RequestStatus.PENDING;
}
public Request(Post post,User user,RequestStatus requestStatus){
this.post = post;
this.user = user;
this.requestStatus = requestStatus;
}
public void updateStatus(UpdateRequestDto updateRequestDto) {
this.requestStatus = updateRequestDto.getStatus();
}
}
@Query("SELECT r from Request r join fetch r.post join fetch r.user where r.id=:id")
Optional<Request> findById_fetchUserAndPost(Long id);
request entity의 Post와 User의 FetchType이 lazy로 설정되어있어 하위 entity인 Post와 User를 참조할 경우 왼쪽의 그림처럼 N+1 쿼리 문제가 발생한다. fetch join을 이용하여 findbyId함수를 위의 JPQL로 바꾸면 오른쪽의 그림처럼 N+1 문제가 해결된다.
explain select * from springdb.request where springdb.request.request_id = 291;
explain select * from springdb.post where springdb.post.post_id = 198;
explain select * from springdb.user where springdb.user.user_id = 99;
explain select * from springdb.request as R join springdb.post as P on P.post_id = R.post_id join springdb.user U on U.user_id = R.user_id where R.request_id = 291;
검색되는 rows 값은 3으로 동일하지만 N+1 쿼리 문제가 발생하는 쿼리들의 duration을 합쳐보면 0.00095175 , N+1 쿼리 문제를 해결한 쿼리는 duration은 0.00044975이다. 쿼리 속도가 2배 이상 개선된 것을 볼 수 있다.
728x90