Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 나의 미팅 조회 :: 리펙터링, 쿼리최적화 #508

Closed
wants to merge 11 commits into from

Conversation

progress0407
Copy link
Collaborator

@progress0407 progress0407 commented Oct 13, 2022

새로운 PR로 재등록합니다

close #507

PR 타입(하나 이상의 PR 타입을 선택해주세요)

  • 기능 추가
  • 기능 삭제
  • 버그 수정
  • 리팩토링
  • 의존성, 환경 변수, 빌드 관련 코드 업데이트

반영 브랜치

feature/be/meeting-find-all-by-me -> dev

요구사항

  • 나의 미팅 조회 /meetings/me 에 대해
    • 리펙터링
    • 쿼리 최적화

변경사항

MeetingAcceptanceTest.findMy 에 대해 응답시간, 쿼리 수 비교

  • 리펙터링 전
    image

  • 리펙터링 후
    image

쿼리 5번이 나가는 이유

image

  • Meeting + Participant 조회 (fetch join) 1

    • 각 조회 결과(Meeting)에 대해
      • Participant와 지각횟수 조회 1
      • 다가오는 이벤트 조회 1
  • 5번: 1 + 2 * (1+ 1)

Event Join 제거

select count(a) "
        +   "from Attendance a "
        + "  inner join a.event e "
        +   "where a.participant.id = p.id and a.status = 'TARDY' and a.disabled = false and e.date <= :date
  • Event 있는 경우
@Query("select p as participant, "
        +   "(select count(a) "
        +   "from Attendance a "
        + "  inner join a.event e "
        +   "where a.participant.id = p.id and a.status = 'TARDY' and a.disabled = false and e.date <= :date) "
        +   "as tardyCount "
        + "from Participant p join fetch p.user "
        + "where p in :participants")
List<ParticipantAndCount> countParticipantsTardy(@Param("participants") final List<Participant> participants,
                                                    @Param("date") final LocalDate date);
  • Event가 없는 경우
@Query("select p as participant, "
        +   "(select count(a) "
        +   "from Attendance a "
        +   "where a.participant.id = p.id and a.status = 'TARDY' and a.disabled = false) "
        +   "as tardyCount "
        + "from Participant p join fetch p.user "
        + "where p in :participants")
List<ParticipantAndCount> countParticipantsTardy_2(@Param("participants") final List<Participant> participants);

리펙터링 전

호출 순서

  • findAllByUserId
    • generateMyMeetingResponse
      • getMeetingAttendances
      • countTardyByParticipant
    • EventResponse.of
private MyMeetingResponse generateMyMeetingResponse(final Participant participant, final LocalDate today) {
    final Meeting meeting = participant.getMeeting();
    final boolean isLoginUserMaster = participant.getIsMaster();

    final MeetingAttendances meetingAttendances = getMeetingAttendances(meeting, today);
    final boolean isCoffeeTime = meetingAttendances.isTardyStackFull();
    final int tardyCount = countTardyByParticipant(participant, meetingAttendances);

    final Optional<Event> upcomingEvent = eventRepository
            .findFirstByMeetingIdAndDateGreaterThanEqualOrderByDate(meeting.getId(), today);
    if (upcomingEvent.isEmpty()) {
        return MyMeetingResponse.of(
                meeting, tardyCount, isLoginUserMaster, isCoffeeTime, false, null
        );
    }
    final Event event = upcomingEvent.get();
    final LocalTime startTime = event.getStartTime();
    final boolean isActive = event.isSameDate(today) && serverTimeManager.isAttendanceOpen(startTime);
    final LocalTime attendanceOpenTime = serverTimeManager.calculateOpenTime(startTime);
    final LocalTime attendanceClosedTime = serverTimeManager.calculateAttendanceCloseTime(startTime);
    return MyMeetingResponse.of(meeting, tardyCount, isLoginUserMaster, isCoffeeTime, isActive, EventResponse.of(event, attendanceOpenTime, attendanceClosedTime));
}
private MeetingAttendances getMeetingAttendances(final Meeting meeting, final LocalDate today) {
    final List<Long> participantIds = meeting.getParticipantIds();
    final List<Attendance> foundAttendances = attendanceRepository
            .findByParticipantIdInAndEventDateLessThanEqual(participantIds, today);
    return new MeetingAttendances(foundAttendances, participantIds.size());
}
private int countTardyByParticipant(final Participant participant, final MeetingAttendances meetingAttendances) {
    final ParticipantAttendances participantAttendances = meetingAttendances
            .extractAttendancesByParticipant(participant);
    return participantAttendances.countTardy();
}
public static EventResponse of(final Event event,
                                final LocalTime attendanceOpenTime,
                                final LocalTime attendanceClosedTime) {
    return new EventResponse(
            event.getId(),
            attendanceOpenTime.format(TIME_FORMATTER),
            attendanceClosedTime.format(TIME_FORMATTER),
            event.getStartTime().format(TIME_FORMATTER),
            event.getEndTime().format(TIME_FORMATTER),
            event.getDate()
    );
}

리펙터링 후

호출 순서

  • findAllByUserId
    • getMyMeetingsResponse
      • getMyMeetingResponse
private List<MyMeetingResponse> getMyMeetingsResponse(final Long userId,
                                                        final List<Meeting> meetings,
                                                        final LocalDate today) {
    final List<MyMeetingResponse> myMeetingResponses = new ArrayList<>();
    for (final Meeting meeting : meetings) {
        final List<ParticipantAndCount> participantAndCounts =
                queryRepository.countParticipantsTardy(meeting.getParticipants());
        meeting.allocateParticipantsTardyCount(participantAndCounts);
        meeting.isTardyStackFull();
        meeting.isMaster(userId);
        final Event upcomingEvent = eventRepository
                .findFirstByMeetingIdAndDateGreaterThanEqualOrderByDate(meeting.getId(), today)
                .orElse(null);
        MyMeetingResponse myMeetingResponse = getMyMeetingResponse(userId, today, meeting, upcomingEvent);
        myMeetingResponses.add(myMeetingResponse);
    }
    return myMeetingResponses;
}
private MyMeetingResponse getMyMeetingResponse(final Long userId,
                                                final LocalDate today,
                                                final Meeting meeting,
                                                final Event upcomingEvent) {
    boolean isActive = false;
    EventResponse eventResponse = null;
    if (upcomingEvent != null) {
        isActive = upcomingEvent.isActive(today, serverTimeManager);
        final LocalTime attendanceOpenTime = upcomingEvent.getOpenTime(serverTimeManager);
        final LocalTime attendanceClosedTime = upcomingEvent.getCloseTime(serverTimeManager);
        eventResponse = EventResponse.of(upcomingEvent, attendanceOpenTime, attendanceClosedTime);
    }
    return new MyMeetingResponse(
            meeting.getId(), meeting.getName(),
            meeting.getTardyCount(), meeting.isMaster(userId),
            meeting.isTardyStackFull(),
            isActive,
            eventResponse
    );
}

@progress0407 progress0407 added 🌾 backend Anything related to back-end 🛠 refactor Refactor code labels Oct 13, 2022
@progress0407 progress0407 self-assigned this Oct 13, 2022
@github-actions
Copy link

Unit Test Results

0 tests   0 ✔️  0s ⏱️
0 suites  0 💤
0 files    0

Results for commit c0947a1.

@github-actions
Copy link

📝 Test Coverage Report

File Coverage [96.11%] 🍏
ParticipantAttendances.java 100% 🍏
MeetingResponse.java 100% 🍏
Event.java 100% 🍏
Participant.java 100% 🍏
MeetingService.java 98.92% 🍏
Meeting.java 95.12% 🍏
ServerTimeManager.java 83.93% 🍏
MyMeetingResponse.java 60%
Total Project Coverage 93.75% 🍏

@github-actions
Copy link

📊 checkmate-sonarqube-508 분석 결과 확인하기 링크

@progress0407 progress0407 deleted the feature/be/meeting-find-all-by-me branch October 14, 2022 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🌾 backend Anything related to back-end 🛠 refactor Refactor code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BE] 나의 미팅 조회 :: 리펙터링, 쿼리최적화
2 participants