문제상황
ERD구조는 위와 같은 상황에서 유저들의 목록을 가져오는데 부서이름과 직급이 필요했다.
데이터베이스에서는 회원 총 21명, 부서 5개, 직책 5개가 존재했다.
ResponseDTO
그래서 리스트 각각에는 밑과 같은 ResponseDTO정보들을 넣어주었다.
@Data
@Builder
public class UserListResponseDTO {
private Long id;
private String name;
private String email;
private Role role;
private String profileImage;
private String departmentName;
private String positionName;
//DTO메서드로 재사용성을 높임
public static UserListResponseDTO toDTO(User user) {
return UserListResponseDTO.builder()
.id(user.getId())
.name(user.getName())
.email(user.getEmail())
.role(user.getRole())
.profileImage(user.getProfileImage())
.departmentName(user.getDepartment().getDepartment_name())
.positionName(user.getPosition().getPosition_name())
.build();
}
}
Service
@Override
@Transactional(readOnly = true)
public List<UserListResponseDTO> listUsers() {
return userRepository.findAll().stream()
.map(UserListResponseDTO::toDTO)
.collect(Collectors.toList());
}
이처럼 서비스를 통해 유저 목록을 조회할 때, 각 유저에 대해 부서와 직급 정보를 가져오는 과정에서 N+1 문제가 발생했습니다. 구체적으로는 다음과 같은 쿼리들이 실행되었습니다:
N+1문제
연관관계에서 발생하는 이슈로 연관 관계가 설정된 엔티티를 조회할 경우에 조회된 데이터 갯수(부서 5개, 직급 5개) 만큼 연관된 엔티티를 조회하기 위해 추가적으로 발생하는 문제
- 유저 21명을 조회하는 쿼리 1번
- 각 유저에 대한 부서 정보를 조회하는 쿼리 5번
- 각 유저에 대한 직급 정보를 조회하는 쿼리 5번
총 11번의 쿼리가 발생했다. 이는 각 유저에 대해 부서와 직급 정보를 지연 로딩(Lazy Loading)으로 가져오기 때문에 발생하는 문제입니다. 동일한 부서와 직급을 가진 유저들이 많아 실제 쿼리 실행 횟수는 줄어들었지만, 여전히 비효율적이었다.
따라서 이 부분을 조금 더 효율적으로 쿼리를 한번만 날려서 모든 정보를 가져오고 싶었기에 Fetch Join을 사용하였다.
해결방법 : Fetch Join
유저를 가져오는데 유저와 연관된 부서 그리고 직책을 가져오는 Fetch Join을 사용하였다.
Repository
@Query("SELECT u FROM User u JOIN FETCH u.department JOIN FETCH u.position")
List<User> findAllWithDepartmentAndPosition();
Service
@Override
@Transactional(readOnly = true)
public List<UserListResponseDTO> listUsers() {
List<User> users = userRepository.findAllWithDepartmentAndPosition();
return users.stream()
.map(UserListResponseDTO::toDTO)
.collect(Collectors.toList());
}
이처럼 Fetch Join을 사용하여 한번의 쿼리 요청으로 유저와 연관된 부서와 직책을 가져올 수 있다. 이렇게 함으로써 N+1문제를 해결하고 쿼리 성능을 향상시킬 수 있었다.
성능테스트에 대한 글은 밑을 통해 알아보자.
[Jmeter] Jmeter를 활용해서 10만건에 대해 성능 테스트(2.7배 향상)
N+1문제를 @Query 와 Fetch join을 통해 해결했다. 근데 이것이 실제로 성능이 개선되었는지 검증을 해야 한다고 생각이 들었고, Jmeter를 활용해서 테스트를 진행해보겠다. 1. Jmeter 설치 Apache JMeter -
eungae-d.tistory.com
'프로젝트 > WMS' 카테고리의 다른 글
[CI/CD] EC2+도커+젠킨스+NIGNX 배포하기 (2) (0) | 2024.11.04 |
---|---|
[CI/CD] EC2+도커+젠킨스+NIGNX 배포하기 (1) (1) | 2024.11.04 |
[AWS/S3] Spring에서 S3에 데이터 저장하기 (0) | 2024.08.06 |
Spirng Security + JWT + OAUTH2 를 활용한 일반로그인, 소셜로그인(Kakao) (2) (0) | 2024.07.03 |
Spirng Security + JWT + OAUTH2 를 활용한 일반로그인, 소셜로그인(Kakao) (1) (1) | 2024.07.02 |