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

refactor: ReactionLog 복합 인덱스를 이용한 API 성능 개선 #359

Merged
merged 1 commit into from
Sep 4, 2024

Conversation

its-sky
Copy link
Member

@its-sky its-sky commented Sep 3, 2024

🌱 관련 이슈

📌 작업 내용 및 특이사항

  • 알림 조회 API 수행시간 개선을 위해 SQL 실행 계획을 분석하였습니다.

  • SQL문 분석 결과 FriendLogEntity 테이블의 쿼리는 PK 인덱스를 정상적으로 잘 탔지만, ReactionLogEntity 쿼리 실행 계획 분석 결과 풀 테이블 스캔이 발생함을 찾아냈습니다. (참고 사항 사진 참조해주세요!)

  • Using filesort: 이 부분이 성능 문제를 야기할 수 있습니다. filesort는 MySQL이 인덱스를 사용하지 않고 디스크에 임시 파일을 만들어 정렬 작업을 수행하고 있음을 의미합니다. 이는 정렬 작업이 많아질수록 성능 저하를 초래할 수 있습니다. 따라서 이를 개선하기 위해 join 비용을 줄이고 receiver_id를 필드에 추가하였습니다.

  • 순차적인 개선을 하였습니다.

  • 먼저 기존 API를 테스트 한 사진을 첨부합니다. [사진 - 참조1]

  • 먼저 receiver_id를 테이블 필드로 추가하여 join 비용을 줄였습니다. [사진 - 참조2]

  • 인덱스를 적용하여 수행 시간을 줄였습니다. [사진 - 참조3]

배포 시 수행해야 할 것

  1. 기존 ReactionLogEntity에 receiver_id 필드를 추가
  2. receiver_id 필드에 ReactionLogEntity의 Reaction의 Memory의 Member의 id를 주입하는 스크립트 수행
ALTER TABLE reaction_log_entity ADD COLUMN receiver_id BIGINT;

UPDATE reaction_log_entity rle
JOIN reaction_entity r1 ON r1.reaction_id = rle.reaction_id
JOIN memory_entity m ON m.memory_id = r1.memory_id
JOIN member_entity m2 ON m2.member_id = m.member_id
SET rle.receiver_id = m2.member_id
WHERE rle.receiver_id IS NULL;

CREATE INDEX idx_receiver_created_at ON reaction_log_entity (receiver_id, created_at);

📝 참고사항

[ReactionLogEntity Using filesort 발생]
image

[참조1 - 기존 API 수행시간 (조회 1000건 수행 - 평균 23ms)]
스크린샷 2024-09-03 오후 5 20 21

[참조2 - receiver_id 필드 추가 (조회 1000건 수행 - 평균 13ms / 기존 대비 1.76배 개선)]
image

[참조3 - (receiver_id, created_at) 복합 인덱스 추가 (조회 1000건 수행 - 평균 6ms / 기존 대비 3.83배 개선)]
image


하지만 1000건 조회이기 때문에 JVM warmup에 따른 편차가 존재할 수 있어 10만건 단위로 조회해보았습니다.
[기존 방식]
스크린샷 2024-09-03 오후 5 48 39

[receiver_id 필드 추가]
스크린샷 2024-09-03 오후 5 43 36

[복합 인덱스 추가]
스크린샷 2024-09-03 오후 5 45 14

해당 결과에서 주의해야 할 건 최대값은 복합 인덱스 추가에서 가장 많이 나왔지만 해당 결과는 outlier이기 때문에 무시해주시면 됩니다. 중요하게 보아야 할 것은 처리량, 수신 KB, 전송 KB 입니다. 개선할수록 해당 값이 높게 나와 성능이 향상된 것을 볼 수 있습니다. 로컬호스트에서는 데이터가 많지 않아 해당 차이가 적지만, 운영을 하면 할수록 해당 API 성능 격차는 점점 커질 것으로 예상됩니다.


복합 인덱스의 효과를 확인하기 위해 cursorCreatedAt 파라미터를 넣고 수행해보았습니다.
[기존 API (조회 1000건 수행 / 평균 9ms]
image

[개선된 API (조회 1000건 수행 / 평균 6ms]
스크린샷 2024-09-03 오후 6 19 22

@its-sky its-sky self-assigned this Sep 3, 2024
Copy link

github-actions bot commented Sep 3, 2024

Test Results

66 tests   66 ✅  2s ⏱️
17 suites   0 💤
17 files     0 ❌

Results for commit a77b6e1.

@its-sky its-sky changed the title refactor: Reaction 로그 구조 변경 및 API turnaround time 개선 refactor: ReactionLog 복합 인덱스를 이용한 API 성능 개선 Sep 3, 2024
Copy link
Collaborator

@penrose15 penrose15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다! 두가지 질문이 있는데요

  1. reaction과 연관관계를 맺고 있는 memory와 member 를 조인했을 때는 fileSort가 일어나지 않은 이유가 궁금합니다. 추측상으로는 reaction의 PK가 reactionLog의 createdAt로 같이 정렬이 되어 연관된 member와 memory도 같이 정렬이 된 걸까요?
  2. 혹시 수정된 이후의 mysql 실행 계획도 볼 수 있을까요?

@its-sky
Copy link
Member Author

its-sky commented Sep 3, 2024

수고하셨습니다! 두가지 질문이 있는데요

  1. reaction과 연관관계를 맺고 있는 memory와 member 를 조인했을 때는 fileSort가 일어나지 않은 이유가 궁금합니다. 추측상으로는 reaction의 PK가 reactionLog의 createdAt로 같이 정렬이 되어 연관된 member와 memory도 같이 정렬이 된 걸까요?
  2. 혹시 수정된 이후의 mysql 실행 계획도 볼 수 있을까요?
  1. 일단 원래도 조인을 하고 있었고 현재도 조인을 합니다! 다만 현재 file sort가 일어나지 않는 이유는 where 절의 필드가 모두 복합 인덱스에 포함이 되어 index를 타게 됩니다. 이전에는 조인을 한 member 테이블에서 where 조건문을 걸고 있었기 때문에 file sort가 발생했습니다!

  2. 새로 바뀐 쿼리 실행계획입니다 :)

image

@penrose15
Copy link
Collaborator

  • ) 지금도 매우 훌륭하지만, 쿼리 실행결과 보니 backwarding index scan 이 발생하고 있는것을 볼 수 있는데요,

이를 해결하기 위해서는 인덱스를 역순으로 정렬하는게 좋을 것 같습니다
Before

CREATE INDEX idx_receiver_created_at ON reaction_log_entity (receiver_id, created_at);

After

CREATE INDEX idx_receiver_created_at ON reaction_log_entity (receiver_id, created_at DESC);

이렇게 한번 변경해보시는게 어떨까요?

reference
https://medium.com/naver-cloud-platform/이렇게-사용하세요-mysql-8-0-개발자를-위한-신규-기능-살펴보기-3-indexes-e32249e2dae5
https://tech.kakao.com/posts/351

@its-sky its-sky merged commit f0df8b1 into develop Sep 4, 2024
3 checks passed
@its-sky its-sky deleted the refactor/357-reaction-log branch September 4, 2024 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

♻️ ReactionLog 인덱스 적용되도록 리팩토링
2 participants