항해99

항해99 78일차 TIL1 - 최종 프로젝트 더 개선하기 - 일정 생성 (1)

자몽포도 2023. 3. 13. 21:53

실전 프로젝트가 이제 2일 밖에 남지 않았어요. 지난 토요일을 끝으로 3월 15일 까지는 더 이상의 main 브랜치 merge는 일어나지 않을거에요. FE 분들과는 구두로 프로젝트를 이어나가자고 했지만 프로젝트가 끝이나면 다들 바빠지시겠죠. 그런 생각이 드니까 더 아쉽다는 생각이 드네요. 

 

하지만 사실 그럴 때가 아니었어요. 지난주부터 문서작성, 발표준비(제가 발표를 잘 못해서 시간이 좀 걸렸어요...ㅎ)하랴 프로젝트에 신경을 많이 못썼답니다.

 

오늘은 그님스에서 많은 리소스를 사용하는 일정 생성 로직을 개선해보려고 합니다.

 

그님스 일정 도메인 이해하기


엔티티 연관 관계

 

우선 사용자(users)와 일정(Event)는 N : M 관계입니다. 테이블 2개로는 N : M 을 풀 수 없기에 중간에 연결 엔티티를 두고 연결엔티티(Schedule)가 사용자(users)와 일정(Event)을 @ManyToOne 으로 연관관계를 맺고 있습니다.

Event 와는 양방향 설정입니다. (서로 뽑아먹을게 많아서 ㅎㅎ)

 

 

일정 생성 로직 이해하기

일정은 두 가지로 나눌 수 있습니다.

1. 개인 일정

2. 공동 일정

 

 

개인 일정

개인 일정의 경우 간단하게 일정을 생성하고 끝을 맺습니다. 

일정 생성을 위해 사용자를 찾고 일정/연결 엔티티(Schedule)를 저장합니다. 

쿼리는 총 3번이 나가게 됩니다.

 

 

 

공동 일정

공동 일정은 조금 복잡합니다.

 

일정이 생성되면 참여자로 선택한 사람들에게 일정에 초대합니다. 그리고 알림까지 전송하게 됩니다.

 

중요한 것은 개인 일정 생성보다 더 복잡하다는 것입니다.

개인 일정 생성과는 다르게 데이터베이스에 접근해야할 이유가 2가지가 증가합니다.

 

1. 일정에 초대된 사람들을 불러와야합니다. 

그래야 연결테이블(Schedule)을 생성하고 알림을 보낼 수 있습니다.

2. 알림을 저장해야 합니다.

 

여기서 쿼리가 예상치 못하게 많이 나갈 수 있는데요. 그 이유는 두 가지입니다.

 

1. 일정에 초대하려는 사람들이 팔로우인지를 확인해야 합니다.

2. 복수명이 일정에 초대될 수 있습니다. (연결, 알림 엔티티 생성에 영향을 미침)

 


제가 개발에 집중하다보니 최적화에 신경을 쓰지 못했습니다... 

 

일정에 4명에 초대했을 경우, 총 17번의 쿼리가 나가더라구요....ㅎ 일정에 초대하는 인원이 더 많아지면 SQL 기하급수적으로 증가하게 되겠죠? 개선해보도록 하겠습니다.

개선 전 알림 엔티티 저장 로직

create 메소드가 루프를 타고 반복적으로 실행되고 있습니다. 

그래서 User 조회 Notification 저장 로직이 초대 인원만큼 발생하게 됩니다.

 

이런식의 쿼리가 초대 받은 인원 만큼 추가로 나갑니다. 이제 로직을 개선해봅시다.

 

 


개선 후 알림 엔티티 저장 로직

 

성능개선은 아래 두 부분에서 일어납니다.

 

 

findAllById를 사용하기 때문에 더 이상 일정 추가 때마다 User를 찾지 않습니다. 유저 조회를 위한 추가 쿼리가 나가지 않게 되죠. 결과 개선 전 쿼리 16번 개선 후 쿼리 13번

원래라면 초대 인원 만큼(4번) SELECT 쿼리가 나갔겠지만 이제는 한 번에 SELECT 하기 때문에 3번이 감소했습니다.

 

다음으로는 saveAll의 경우 쿼리 호출 자체를 줄이는 것은 아니지만 트랜잭션 호출이 감소합니다.

save() 의 경우 1건 마다 트랜잭션이 생성되고 커밋을 하지만 saveAll 의 경우 N건이더라도 트랜잭셔 하나에서 모두를 커밋합니다. 예시에서는 초대 인원이 4명이였기에 드라마틱하게 효과를 보진 못하겠지만 해당 API 호출이 잦거나 초대 인원이 엄청나게 많다면 성능 차이가 분명할 것입니다. 

 


그럼 여기서 개선이 끝난 것일까요? 저는 아래 부분이 조금 거슬리네요.

 

create 메서드가 두 개나 되는게 맞을까요? 현 상태를 유지한다면 일정 생성이 아닌 다른 곳에서 N명에게 알림을 보내려면 create 메서드를 또 다시 오버로딩 해야합니다. 다음 번에는 이 문제를 해결해보도록 하겠습니다.