이렇게 이루어진 ERD 모델이 있다. (예시)
조건에 맞춰 불러오고자 하는 Data는 세 테이블의 정보를 모두 필요로 한다.
이때 Fetch join을 고려해볼 수 있다.
Permission 입장에서 user와 document를 두번 다 fetch join 할 수 있지만, 이능 데이터 베이스 성능 상 엄청난 문제가 있다.
데이터가 많을 경우, 연관된 엔티티의 수를 제한하는 방법으로 쿼리를 나눠서 발생시키는 것도 좋은 방법일 것이다.
해당 엔티티들은 모두 FetchType.LAZY 로 설정되어 있다.
기존 쿼리 :
val documents = documentQueryService.findDocumentsByIdFetchJoinPermissions(projectId)
return Response.UserPermission(
documents.permissions.asSequence()
.filter { it.status != STATUS.DELETED }
.map { Response.UserPermission(it.user, it.permission) }
.toList()
)
- document의 permissions 를 fetch join한 결과를 가지고 it.user를 통해 시퀀스를 돌린다.
- 이때 permission의 개수만큼 user를 select 하는 쿼리가 계속적으로 발생한다.
- DB Connection 낭비 및 불필요한 Query 의 발생
개선 쿼리 :
val documents = documentQueryService.findDocumentsByIdFetchJoinPermissions(projectId)
val permissions = permissionQueryService.findPermissionsWithFetchJoinUsers(project.permissions)
return Response.UserPermission(
documents.permissions.asSequence()
.filter { it.status != STATUS.DELETED }
.map { Response.UserPermission(it.user, it.permission) }
.toList()
)
- user 를 불러오는 쿼리를 없애기 위해 user와 permission을 fetchjoin 하는 쿼리를 추가로 발생시켰다.
- 이렇게 하면 user 들을 따로 select하는 쿼리가 발생하지 않는다.
- 이런식으로 one to many 관계의 fetch join을 동시에 하는 것이 아닌 나눠서 발생시키는 것으로 쿼리 개수를 줄일 수 있다.
고찰
백엔드의 API 성능을 개선하는 방법은 정답이 없다.
상황에 맞게 타협을 봐야 하는 부분도 당연히 고려해야한다.
보통 백엔드에서 성능을 가장 많이 개선시킬 수 있는 부분은 DB와의 커넥션이므로, JPA를 이용하여 SQL을 잘 발생시키면 대부분의 성능 문제는 해결할 수 있을 것으로 보인다.
실제로 확연하게 차이난 결과를 보면 그 이점을 확실히 알 수 있을 것이다.
(user data가 5개 밖에 없는데도 두배 이상 차이난 것은, 데이터가 많아질 경우, 확실하게 성능 개선이 이루어진 것을 확인할 수 있다.)
이러한 방법을 통해 더 확실하게 백엔드의 성능적 고민과 해결을 잘 해나가리라 다짐해본다.
반응형
'📕 Spring Framework > Spring 개념 정리' 카테고리의 다른 글
Bean 등록에 대한 재고 (1) | 2024.10.12 |
---|---|
Spring boot multi datasource 등록 시 주의 사항 (0) | 2024.09.18 |
[Reactive Programming] 비동기-논블로킹 프로그래밍 (2) | 2023.02.11 |
[@DataJpaTest] h2 인메모리 db를 이용한 테스트 설정 방법 (0) | 2022.12.21 |
WebFlux는 무엇이고, 왜 나왔고, 언제 쓰이는가? (0) | 2022.08.31 |